title: How to remove user profiles with PowerShell
body: <p>I have the script below. If I uncomment the line commented <code>#3</code>, I get the error</p>
  
  <pre><code>Exception calling "Delete" with "0" argument(s): ""
  At Z:\Scripts\Powershell\Remove-UserProfile.ps1:48 char:21
  +                     $Profile.Delete()
  +                     ~~~~~~~~~~~~~~~~~
      + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
      + FullyQualifiedErrorId : DotNetMethodException
  </code></pre>
  
  <p>regardless of whether I interrogate WMI using the format in <code>#1</code> or <code>#2</code>.  If I leave <code>#3</code> commented, and uncomment <code>#4</code>, I get the error</p>
  
  <pre><code>Remove-WmiObject : 
  At Z:\Scripts\Powershell\Remove-UserProfile.ps1:49 char:21
  +                     Remove-WmiObject -InputObject $Profile
  +                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      + CategoryInfo          : InvalidOperation: (:) [Remove-WmiObject], COMException
      + FullyQualifiedErrorId : RemoveWMICOMException,Microsoft.PowerShell.Commands.RemoveWmiObject
  </code></pre>
  
  <p>regardless of the query string for <code>Get-WMIObject</code>.</p>
  
  <p>Everything I can find on the web - including a couple of other SO questions - implies that either of these methods should work, but neither seems to. I have checked to see if the target profile is loaded, and it is not. Why can I not use WMI to delete user profiles? What can I do that <em>does</em> work, and doesn't involve downloading a utility from a third-party (which is not permitted by our "information security" team)?</p>
  
  <p>Script:</p>
  
  <pre><code>function Remove-UserProfile {
  &lt;#
  .SYNOPSIS
  Removes user profiles from computers
  #&gt;
  
      [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact="High")]
  
      param(
          [Parameter(ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
          [String[]]$ComputerName = $env:ComputerName,
  
          [Alias("UserName","sAMAccountName")]
          [String]$Identity,
  
          [Int]$Age,
  
          [Switch]$DomainOnly
      )
  
      BEGIN {
          $NoSystemAccounts = "SID!='S-1-5-18' AND SID!='S-1-5-19' AND SID!='S-1-5-20' " # Don't even bother with the system accounts.
          if ($DomainOnly) {
              $SIDQuery = "SID LIKE '$((Get-ADDomain).DomainSID)%' "                      # All domain account SIDs begin with the domain SID
          } elseif ($Identity.Length -ne 0) {
              $SIDQuery = "SID LIKE '$(Get-UserSID -AccountName $Identity)' "
          }
          $CutoffDate = (Get-Date).AddDays(-$Age)
          $Query = "SELECT * FROM Win32_UserProfile "
      }
  
      PROCESS{
          ForEach ($Computer in $ComputerName) {
              Write-Verbose "Processing Computer $Computer..."
              if ($SIDQuery) {
                  $Query += "WHERE " + $SIDQuery
                  $FilterStr = $SIDQuery
              } else {
                  $Query += "WHERE " + $NoSystemAccounts
                  $FilterStr = $NoSystemAccounts
              }
              Write-Verbose "Querying WMI using '$Query' and filtering for profiles last used before $CutoffDate ..."
  #1            $Profiles = Get-WMIObject -Query $Query | Where-Object { [Management.ManagementDateTimeConverter]::ToDateTime($_.LastUseTime) -lt $CutoffDate }
  #2            $Profiles = Get-WMIObject -ComputerName $Computer -Class Win32_UserProfile -Filter $FilterStr | Where-Object { [Management.ManagementDateTimeConverter]::ToDateTime($_.LastUseTime) -lt $CutoffDate }
              ForEach ($Profile in $Profiles) {
                  if ($PSCmdlet.ShouldProcess($Profile)) {
  #3                    $Profile.Delete()
  #4                    Remove-WmiObject -InputObject $Profile
                  }
              }
          }
      }
  
      END {}
  }
  </code></pre>