We help IT Professionals succeed at work.

What needs to exist in a PowerShell script to assure Get-WMIObject works?

Hello Expert,

My goal is to export the desktop computer names from active directory, place the output into a text file and loop the names through the script to determine the administrator accounts on over 700 desktops.  When I tested the script I received an error:

"Get-WmiObject: The RPC is unavailable
     $AllLocalAccounts = Get-WmiObject -Class ...
   + CategoryInfo: Invalid Operation: (:) ... "

What is the script missing the 'AllLocalAccounts' variable? What is the best syntax?
Set-StrictMode -Version Latest
Set-ExecutionPolicy remotesigned -Force
import-module activedirectory

Get-ADComputer -Filter '*' -SearchBase "OU=Computers,DC=company,DC=com" -Properties Name | Select Name |  Out-File C:\Scripts\DesktopAccounts.txt


Param
(
	[Parameter(Position=0,Mandatory=$false)]
	[ValidateNotNullorEmpty()]
	[Alias('cn')][String[]]$ComputerName=(get-content c:\Scripts\DesktopAccounts.txt),
	[Parameter(Position=1,Mandatory=$false)]
	[Alias('un')][String[]]$AccountName,
	[Parameter(Position=2,Mandatory=$false)]
	[Alias('cred')][System.Management.Automation.PsCredential]$Credential
)
	
$Obj = @()

Foreach ($Computer in $ComputerName)
{
	If($Credential)
	{
		$AllLocalAccounts = Get-WmiObject -Class Win32_UserAccount -Namespace "root\cimv2" `
		-Filter "LocalAccount='$True'" -ComputerName $Computer -Credential $Credential -ErrorAction Stop
	}
	else
	{
		$AllLocalAccounts = Get-WmiObject -Class Win32_UserAccount -Namespace "root\cimv2" `
		-Filter "LocalAccount='$True'" -ComputerName $Computer -ErrorAction Stop
	}
	
	Foreach($LocalAccount in $AllLocalAccounts)
	{
		
        Set-ExecutionPolicy remotesigned -Force
        Import-Module activedirectory

        Set-StrictMode -Version Latest

        $Object = New-Object -TypeName PSObject
		
		$Object|Add-Member -MemberType NoteProperty -Name "User Name" -Value $LocalAccount.Name
		$Object|Add-Member -MemberType NoteProperty -Name "Full Name" -Value $LocalAccount.FullName
		$Object|Add-Member -MemberType NoteProperty -Name "Logon Account Caption" -Value $LocalAccount.Caption
      	$Object|Add-Member -MemberType NoteProperty -Name "Disabled" -Value $LocalAccount.Disabled
		$Object|Add-Member -MemberType NoteProperty -Name "Status" -Value $LocalAccount.Status
		$Object|Add-Member -MemberType NoteProperty -Name "LockOut" -Value $LocalAccount.LockOut
		$Object|Add-Member -MemberType NoteProperty -Name "Password Changeable" -Value $LocalAccount.PasswordChangeable
		$Object|Add-Member -MemberType NoteProperty -Name "Password Expires" -Value $LocalAccount.PasswordExpires
		$Object|Add-Member -MemberType NoteProperty -Name "Password Required" -Value $LocalAccount.PasswordRequired
		$Object|Add-Member -MemberType NoteProperty -Name "Domain" -Value $LocalAccount.Domain
		$Object|Add-Member -MemberType NoteProperty -Name "Description" -Value $LocalAccount.Description
		
		$Obj+=$Object
	}
	
	If($AccountName)
	{
		Foreach($Account in $AccountName)
		{
		    $Obj| Where-Object{$psitem.Name -like "$Account"} 
		}
	}
	else
	{
		    $Obj | Export-csv c:\Scripts\DesktopAccounts.csv
	}
}

Open in new window

Comment
Watch Question

Qlemo"Batchelor", Developer and EE Topic Advisor
Top Expert 2015

Commented:
The issue is that you do not check for reachability of the remote machines. Get-WMIObject times out and throws that error at you.
Will SzymkowskiSenior Solution Architect
Most Valuable Expert 2015
Top Expert 2015

Commented:
Get-WmiObject: The RPC is unavailable
WMI uses the RPC service to get the information you are querying. You can receive the above message for the following reasons...
- computer is not pingable
- computer is powered off
- firewall on computer
- RPC service is stopped/disabled.

Will.
Qlemo"Batchelor", Developer and EE Topic Advisor
Top Expert 2015

Commented:
I've changed that part, inserting a ping and doing nothing if no success.
But note that in your line 68 you will write to a single CSV file, and do that in a loop - this will always replace the file, and not append info!
Set-StrictMode -Version Latest
Set-ExecutionPolicy remotesigned -Force
import-module activedirectory

Get-ADComputer -Filter '*' -SearchBase "OU=Computers,DC=company,DC=com" -Properties Name | Select Name |  Out-File C:\Scripts\DesktopAccounts.txt


Param
(
  [Parameter(Position=0,Mandatory=$false)]
  [ValidateNotNullorEmpty()]
  [Alias('cn')][String[]]$ComputerName=(get-content c:\Scripts\DesktopAccounts.txt),
  [Parameter(Position=1,Mandatory=$false)]
  [Alias('un')][String[]]$AccountName,
  [Parameter(Position=2,Mandatory=$false)]
  [Alias('cred')][System.Management.Automation.PsCredential]$Credential
)
  
$Obj = @()

Foreach ($Computer in $ComputerName)
{
  if (Test-Connection $Computer -Count 1 -TimeToLive 5 -Quiet)
  {
    If($Credential)
    {
      $AllLocalAccounts = Get-WmiObject -Class Win32_UserAccount -Namespace "root\cimv2" `
      -Filter "LocalAccount='$True'" -ComputerName $Computer -Credential $Credential -ErrorAction Stop
    }
    else
    {
      $AllLocalAccounts = Get-WmiObject -Class Win32_UserAccount -Namespace "root\cimv2" `
      -Filter "LocalAccount='$True'" -ComputerName $Computer -ErrorAction Stop
    }
    
    Foreach($LocalAccount in $AllLocalAccounts)
    {
      
          Set-ExecutionPolicy remotesigned -Force
          Import-Module activedirectory

          Set-StrictMode -Version Latest

          $Object = New-Object -TypeName PSObject
      
      $Object|Add-Member -MemberType NoteProperty -Name "User Name" -Value $LocalAccount.Name
      $Object|Add-Member -MemberType NoteProperty -Name "Full Name" -Value $LocalAccount.FullName
      $Object|Add-Member -MemberType NoteProperty -Name "Logon Account Caption" -Value $LocalAccount.Caption
          $Object|Add-Member -MemberType NoteProperty -Name "Disabled" -Value $LocalAccount.Disabled
      $Object|Add-Member -MemberType NoteProperty -Name "Status" -Value $LocalAccount.Status
      $Object|Add-Member -MemberType NoteProperty -Name "LockOut" -Value $LocalAccount.LockOut
      $Object|Add-Member -MemberType NoteProperty -Name "Password Changeable" -Value $LocalAccount.PasswordChangeable
      $Object|Add-Member -MemberType NoteProperty -Name "Password Expires" -Value $LocalAccount.PasswordExpires
      $Object|Add-Member -MemberType NoteProperty -Name "Password Required" -Value $LocalAccount.PasswordRequired
      $Object|Add-Member -MemberType NoteProperty -Name "Domain" -Value $LocalAccount.Domain
      $Object|Add-Member -MemberType NoteProperty -Name "Description" -Value $LocalAccount.Description
      
      $Obj+=$Object
    }
    
    If($AccountName)
    {
      Foreach($Account in $AccountName)
      {
          $Obj| Where-Object{$psitem.Name -like "$Account"} 
      }
    }
    else
    {
          $Obj | Export-csv c:\Scripts\DesktopAccounts.csv
    }
  }
}

Open in new window

Will SzymkowskiSenior Solution Architect
Most Valuable Expert 2015
Top Expert 2015

Commented:
Personally all I would do is use -ErrorAction SilentContinue or Ignore.

Will.

Author

Commented:
Hi,

For some reason the script still doesn't work. Are the parameters right?
Error message - Test-Connection: Cannot validate argument for parameter 'ComputerName' , The argument is null or empty ...

Within the DesktopAccounts.txt file there is only one pingable computer name.

Thank you.
*********************************
Set-StrictMode -Version Latest
Set-ExecutionPolicy remotesigned -Force
import-module activedirectory

Get-ADComputer -Filter '*' -SearchBase "OU=Computers,DC=company,DC=com" -Properties Name | Select Name |  Out-File C:\Scripts\DesktopAccounts.txt

Param
(
  [Parameter(Position=0,Mandatory=$false)]
  [ValidateNotNullorEmpty()]
  [Alias('cn')][String[]]$ComputerName=(Get-Content -path c:\Scripts\DesktopAccounts.txt),
  [Parameter(Position=1,Mandatory=$false)]
  [Alias('un')][String[]]$AccountName,
  [Parameter(Position=2,Mandatory=$false)]
  [Alias('cred')][System.Management.Automation.PsCredential]$Credential
)      

$Obj = @()

Foreach($Computer in $ComputerName)
{
  if (Test-Connection $Computer -Count 1 -TimeToLive 5 -Quiet)
   {
      If($Credential)
      {
            $AllLocalAccounts = Get-WmiObject -Class Win32_UserAccount -Namespace "root\cimv2" `
            -Filter "LocalAccount='$True'" -ComputerName $Computer -Credential $Credential -ErrorAction Stop
      }
      else
      {
            $AllLocalAccounts = Get-WmiObject -Class Win32_UserAccount -Namespace "root\cimv2" `
            -Filter "LocalAccount='$True'" -ComputerName $Computer -ErrorAction Stop
      }
      
      Foreach($LocalAccount in $AllLocalAccounts)
      {
            
        Set-ExecutionPolicy remotesigned -Force
        Import-Module activedirectory

        Set-StrictMode -Version Latest

        $Object = New-Object -TypeName PSObject
            
            $Object|Add-Member -MemberType NoteProperty -Name "User Name" -Value $LocalAccount.Name
            $Object|Add-Member -MemberType NoteProperty -Name "Full Name" -Value $LocalAccount.FullName
            $Object|Add-Member -MemberType NoteProperty -Name "Logon Account Caption" -Value $LocalAccount.Caption
            $Object|Add-Member -MemberType NoteProperty -Name "Disabled" -Value $LocalAccount.Disabled
            $Object|Add-Member -MemberType NoteProperty -Name "Status" -Value $LocalAccount.Status
            $Object|Add-Member -MemberType NoteProperty -Name "LockOut" -Value $LocalAccount.LockOut
            $Object|Add-Member -MemberType NoteProperty -Name "Password Changeable" -Value $LocalAccount.PasswordChangeable
            $Object|Add-Member -MemberType NoteProperty -Name "Password Expires" -Value $LocalAccount.PasswordExpires
            $Object|Add-Member -MemberType NoteProperty -Name "Password Required" -Value $LocalAccount.PasswordRequired
            $Object|Add-Member -MemberType NoteProperty -Name "Domain" -Value $LocalAccount.Domain
            $Object|Add-Member -MemberType NoteProperty -Name "Description" -Value $LocalAccount.Description
            
            $Obj+=$Object
      }
      
      If($AccountName)
      {
            Foreach($Account in $AccountName)
            {
                $Obj| Where-Object{$psitem.Name -like "$Account"}
            }
      }
      else
      {
                $Obj | Export-csv c:\Scripts\SleepMedDesktopGroupMembers.csv -Append -NoTypeInformation
      }
  }
}
Qlemo"Batchelor", Developer and EE Topic Advisor
Top Expert 2015

Commented:
You have empty lines in your file for sure, and that is because you create it the wrong way. You should use this:
Get-ADComputer -Filter '*' -SearchBase "OU=Computers,DC=company,DC=com" -Properties Name | Select -Expand Name |  Out-File C:\Scripts\DesktopAccounts.txt

Open in new window

otherwise the property name ("Name"), additional spacing and some equal signs will appear in the file.

And the code is really bad style, mixing writing into files and into the pipeline, having superfluous code, running a command before PARAM, using cumbersome commands, using fixed file names, etc. pp.
Do you really need the different ways the "command" can be called, according to PARAM definition? If not, the script could be simplified much.

Author

Commented:
Hi QLemo,

Would you please create the simplified version so I may compare?

Thank you kindly,
CuriousMAUser
"Batchelor", Developer and EE Topic Advisor
Top Expert 2015
Commented:
Set-StrictMode -Version Latest
Set-ExecutionPolicy remotesigned -Force
import-module activedirectory

Get-ADComputer -Filter '*' -SearchBase "OU=Computers,DC=company,DC=com" -Properties Name | % {
  $PC = $_.Name

  if (Tst-Connection $PC -Count 1 -TimeToLive 5 -Quiet)
  {
    Get-WmiObject Win32_UserAccount -ComputerName $PC -Filter "LocalAccount='True' | % {
      New-Object PsObject -Property @{
                 "User Name"             = $_.Name
                 "Full Name"             = $_.FullName
                 "Logon Account Caption" = $_.Caption
                 "Disabled"              = $_.Disabled
                 "Status"                = $_.Status
                 "LockOut"               = $_.LockOut
                 "Password Changeable"   = $_.PasswordChangeable
                 "Password Expires"      = $_.PasswordExpires
                 "Password Required"     = $_.PasswordRequired
                 "Domain"                = $_.Domain
                 "Description"           = $_.Description
      }
   }
} | Export-csv c:\Scripts\SleepMedDesktopGroupMembers.csv -NoTypeInformation

Open in new window

Author

Commented:
Thank you! I'm still troubleshooting.

Author

Commented:
Hi QLemo,

With the script below I'm trying to loop through over 700 computer names and extract their user account details to determine how many 'Administrators' have local access. This script loops once. Does the script need to use ForEach logic?

Set-StrictMode -Version Latest
Set-ExecutionPolicy remotesigned -Force
import-module activedirectory

Get-ADComputer -Filter '*' -SearchBase "OU=Computers - SleepMed,DC=sleepmed,DC=md" -Properties Name | % {
  $PC = $_.Name}

  if (Test-Connection $PC -Count 1 -TimeToLive 5 -Quiet)
  {
    Get-WmiObject Win32_UserAccount -ComputerName $PC -Filter "LocalAccount='True'" | % {
      New-Object PsObject -Property @{
                 "User Name"             = $_.Name
                 "Full Name"             = $_.FullName
                 "Logon Account Caption" = $_.Caption
                 "Disabled"              = $_.Disabled
                 "Status"                = $_.Status
                 "LockOut"               = $_.LockOut
                 "Password Changeable"   = $_.PasswordChangeable
                 "Password Expires"      = $_.PasswordExpires
                 "Password Required"     = $_.PasswordRequired
                 "Domain"                = $_.Domain
                 "Description"           = $_.Description
      } | Export-csv -path c:\Scripts\DesktopGroupMembers.csv -NoTypeInformation
    }
}
Qlemo"Batchelor", Developer and EE Topic Advisor
Top Expert 2015

Commented:
No, the loop is already there. Everything found by the Get-ADComputer will get process.

Author

Commented:
Excellent. Thank you so much.