Birdman
Birdman

Reputation: 1524

PowerShell command fails after variable is used

I'm trying to run a command to gather use profiles with certain requirements, here's my code:

#$numberOfDays = 30
#$numberOfDays

$profileStructsToRemove = Get-CimInstance Win32_UserProfile | 
    Where-Object {$_.LastUseTime -lt $(Get-Date).Date.AddDays(-$numberOfDays) } |
    Where-Object {$_.LocalPath.ToUpper() -ne 'C:\USERS\ADMINISTRATOR'} |
    Where-Object {$_.LocalPath.ToUpper() -ne 'C:\USERS\SOME_PROFILE_TO_KEEP'} |
    Where-Object {$_.LocalPath.ToUpper() -ne 'C:\USERS\PUBLIC'}

$profileStructsToRemove #print

I use the $numberOfDays variable to determine the number of days subtracted from today's date that I want to use as the filter. Right now it's commented out, and the command succeeds, although since $numberOfDays isn't defined I assume it's using a null value? I'm not really sure but it works that way...

However, when I assign $numberOfDays to 30, it fails to populate the variable $profileStructsToRemove with ANYTHING at all. It just utterly fails. I could really use some input on why this is happenening.

  1. How is the command working when $numberOfDays isn't defined? Is it just a null value, or treating it as 0 for the AddDays function?
  2. Why is this command failing once $numberOfDays is assigned a value?

Upvotes: 1

Views: 583

Answers (2)

mklement0
mklement0

Reputation: 437363

gms0ulman's helpful answer answers question #1 well (converting $null to an [int] yields 0).

As for question #2:

At least on Windows 11 on a non-domain machine:

  • for currently logged-on accounts (which may include service accounts), the .LastUseTime property seemingly always returns the current date and time
  • unless you run the command with elevation (as administrator), you may see no values for other users' profiles.

For reference, here's the full list of available time stamps:
LastAttemptedProfileDownloadTime, LastAttemptedProfileUploadTime, LastBackgroundRegistryUploadTime, LastDownloadTime, LastUploadTime, LastUseTime.


As for how to optimize the code in your question in general:

  • PowerShell string operators are case-insensitive by default, so there's no need for .toUpper().

  • You could combine your multiple Where-Object calls into a single one, and you can use
    -notin with an array of paths on the RHS, instead of using -ne with individual paths.

To put it all together (PSv3+; keeping in mind that comparing against .LastUsedTime may be pointless):

#requires -RunAsAdministrator
$profileStructsToRemove = 
  Get-CimInstance win32_userprofile |
  Where-Object {
    $_.LastUseTime -lt (Get-Date).Date.AddDays(-$numberOfDays) -and
      $_.LocalPath -notin 'C:\USERS\ADMINISTRATOR',
                          'C:\USERS\SOME_PROFILE_TO_KEEP',
                          'C:\USERS\PUBLIC'
  }

Upvotes: 2

G42
G42

Reputation: 10019

  1. Yes, it's null, which added zero days. This is fine - you can test with:

    $(Get-Date).Date.AddDays($null)
    
  2. Are you sure there are profiles that match that data? Check the data when $numberOfDays is null to confirm.

Upvotes: 1

Related Questions