I am trying to create a PowerShell script that will be executed via a task every day. The task will check if a user has been a member of an AD group longer than 7 days. If so, that user will be removed. The data is imported from a CSV file in which we will insert the date the user was added to the group:
samaccountname,Date
user 1,20/01/2022
user2,06/02/2022
This is the code I wrote:
$users = "C:\Path to CSV\File.csv"
Import-Module ActiveDirectory
Import-Csv $users
foreach ($user in $Users)
{
$CheckDate2 = get-date ($user.'Date').AddDays(7)
$CheckDate1 = get-date ($user.'Date')
if ($CheckDate1 -lt $CheckDate2){
exit
}
else{
Remove-ADGroupMember -Identity "Group Name" -Members $user.samaccountname -Confirm:$false
}
}
This is the errors I am receiving:
You cannot call a method on a null-valued expression.
At line:8 char:1
+ $CheckDate2 = get-date ($user.'Date').AddDays(7)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Get-Date : Cannot bind parameter 'Date' to the target. Exception setting "Date": "Cannot convert null to type "System.DateTime"."
At line:9 char:24
+ $CheckDate1 = get-date ($user.'Date')
+ ~~~~~~~~~~~~~~
+ CategoryInfo : WriteError: (:) [Get-Date], ParameterBindingException
+ FullyQualifiedErrorId : ParameterBindingFailed,Microsoft.PowerShell.Commands.GetDateCommand
Remove-ADGroupMember : Cannot validate argument on parameter 'Members'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
At line:16 char:68
+ ... tity "Group Name" -Members $user.samaccountname -Confir ...
+ ~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Remove-ADGroupMember], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.ActiveDirectory.Management.Commands.RemoveADGroupMember
Your foreach
loop is enumerating $users
, which has a value of "C:\Path to CSV\File.csv"
. This means there will be one iteration of the loop where $user
has a value of "C:\Path to CSV\File.csv"
. Since the [String]
class does not have a Date
property, this...
($user.'Date').AddDays(7)
...is effectively this...
($null).AddDays(7)
...hence the error. You are also not doing anything with the output of Import-Csv $users
, so you need to collect it somewhere for processing; either store it in a variable...
$usersPath = "C:\Path to CSV\File.csv"
Import-Module ActiveDirectory
$users = Import-Csv $usersPath
foreach ($user in $users)
{
# ...
...or, even better, loop directly over the output to process records as they're read...
$usersPath = "C:\Path to CSV\File.csv"
Import-Module ActiveDirectory
foreach ($user in Import-Csv $usersPath)
{
# ...
I renamed your initial $users
variable to $usersPath
for clarity; reusing a variable in that way can be confusing and unexpected.
Even after fixing the loop you still need to change your parentheses from this...
get-date ($user.'Date').AddDays(7)
...to this...
(get-date $user.'Date').AddDays(7)
...to create a [DateTime]
using the value of $user.'Date'
and then call AddDays(7)
on the result. Note that you don't need to quote a property that doesn't contains spaces in the name, so you can simplify that to...
(get-date $user.Date).AddDays(7)
Also, you are comparing a user's Date
with Date + 7d
, which will always be $true
. Instead, you want to test if today is beyond the 7-day membership limit...
$today = (Get-Date).Date # Ignore the TimeOfDay portion so the expiration happens on a day boundary
$userAddedDate = Get-Date ($user.Date)
$maxGroupMembershipTime = New-TimeSpan -Day 7
if ($today - $userAddedDate -gt $maxGroupMembershipTime)
# Alternative: if ($userAddedDate + $maxGroupMembershipTime -lt $today)
{
# ...
Finally, you are conditionally exit
ing the loop, which means no further user records nor anything else in the script will be processed. To skip that user you would replace exit
with continue
, or just let control fall through to the end of the foreach
block...
$usersPath = "C:\Path to CSV\File.csv"
$today = (Get-Date).Date # Ignore the TimeOfDay portion so the expiration happens on a day boundary
$maxGroupMembershipTime = New-TimeSpan -Day 7
Import-Module ActiveDirectory
foreach ($user in Import-Csv $usersPath)
{
$userAddedDate = Get-Date ($user.Date)
if ($today - $userAddedDate -gt $maxGroupMembershipTime)
# Alternative: if ($userAddedDate + $maxGroupMembershipTime -lt $today)
{
Remove-ADGroupMember -Identity "Group Name" -Members $user.samaccountname -Confirm:$false
}
}
I moved the initialization of $today
outside of the loop since there's really no need to set it on each iteration and to ensure every user gets the same date for "today" regardless of when the script executes.