Hello Spice Heads,

What I need, is the following:

  • All Remote Computers

  • Last Authentication Time

  • Operating System

  • Enabled in Active Directory

  • Hardware Information (Model, RAM, Storage, Processor)

  • Serial Number

ETC.

I can pull this info locally, having a hard time for Remote Systems.

Any advice?

God Bless,

-Mike

Script so Far:

import-module activedirectory  
$DaysInactive = 183  #define days 
$time = (Get-Date).Adddays(-($DaysInactive)) 
Get-ADComputer -Filter {LastLogonTimeStamp -lt $time} -Properties whenCreated,whenChanged, LastLogonTimeStamp, Enabled, OperatingSystem  |
 
select-object Name,@{Name="Stamp"; Expression={[DateTime]::FromFileTime($_.lastLogonTimestamp)}}, whenCreated, whenChanged ,Enabled, OperatingSystem 
#| export-csv c:\Reports\OLD_Computer.csv -notypeinformation

9 Spice ups

No, not all that info is in AD, so you have to query each machine for some of that info. e.g.

also be advised that lastLogontimeStamp can be up to 14 days behind.

what makes a computer a ‘remote’ computer? do you have a certain OU for that, or anything else you can filter by?

You’d basically run all the machines though a for each loop and try to connect to them (e.g. with invoke-command or get-ciminstance depending what exactly you need.)

1 Spice up

Yeah, so it would be all Computers on the Network.

All the specs for each system.

ETC…

that means everything and nothing, what are you looking for?

that’s the theory:
you want to add some error handling and such. (e.g. if it does not ping)

import-module activedirectory  
$DaysInactive = 183  
$time         = (Get-Date).Adddays(-$DaysInactive) 

$machines = 
Get-ADComputer -Filter {LastLogonTimeStamp -lt $time} -Properties whenCreated,whenChanged, LastLogonTimeStamp, Enabled, OperatingSystem 

$computerReport = 
foreach($machine in $machines){

    $cpuInfo = Get-CimInstance -ClassName Win32_Processor      -ComputerName $machine.name -ErrorAction SilentlyContinue
    $ramInfo = Get-CimInstance -ClassName Win32_PhysicalMemory -ComputerName $machine.name -ErrorAction SilentlyContinue

    [pscustomobject]@{
        name            = $machine.name
        Stamp           = [DateTime]::FromFileTime($machine.lastLogonTimestamp)
        whenCreated     = $machine.whenCreated
        whenChanged     = $machine.whenChanged
        Enabled         = $machine.Enabled
        Operatingsystem = $machine.Operatingsystem
        CPU             = $cpuInfo.name
        RAM             = "$(($ramInfo.Capacity | Measure-Object -sum).sum / 1GB) GB"

    }
}

$computerReport | 
Export-Csv  "c:\Reports\OLD_Computer-$(get-date -Format 'yyyyMMdd').csv" -NoTypeInformation

Try this one line PowerShell script

Get-ADComputer -Filter * -Properties * | select Name,ObjectID,OperatingSystem,Enabled,LastLogonTimestamp

Firstly, you should not be running PS scripts on such invasive scale to retrieve so much information. If you can do it, that means “others” can do it as well as you would have opened some rather generic local firewall permissions & ports.

I would highly recommend using Inventory software like from Teamviewer, PDQ, or spiceworks to create an Inventory of your hardware then perform scans as you need to update the details.

1 Spice up

that’s bad practice, there is no reason to pull all ( * ) properties if he does not need them, just pull what you need.

Get-ADComputer -Filter * -Properties OperatingSystem,lastlogondate | 
select Name,Enabled,lastlogondate

But then again, that does not take care of the issues that he needs more data than AD can provide.

I agree on inventory software but I’d stay away from TeamViewer.

Bro…may I know why ?? As a remote admin, its expensive as compared to splashtop etc… but if you add in stuff like security, backup (now they have client backup to their AWS storage) and Inventory tool…it kinda makes a bit more sense.

Definitely agreed on the use of an RMM / inventory tool. If you’re looking to just gather something quick (once, maybe twice), you can do so with the above PowerShell provided by Neally. If you have a large number of computers, it could take a while. To speed things up, Get-CimInstance supports asynchornous queries, but requires a bit more code to handle effectively. If you have a fair amount, but not a “lot”, you could use a simple where clause to look things up. If you do have a “lot”, I’d recommend a hashtable with the computer name as key and the value the result. That way you’re not iterating each collection for every computer.

$cpuInfo = Get-CimInstance -ClassName Win32_Processor -ComputerName $machines -ErrorAction SilentlyContinue
$ramInfo = Get-CimInstance -ClassName Win32_PhysicalMemory -ComputerName $machines -ErrorAction SilentlyContinue

I call my “PC Inventory” script my “magnum opus”. I hardly knew PowerShell when I started, and finishing it (so far) has given me massive amounts of knowledge of PS.

To inventory remote PCs, look to the -ComputerName parameter in almost all cmdlets, including Get-ADComputer.

Maybe this will get you a little further down the road:

ForEach ($PC in (Get-ADComputer -Filter {OperatingSystem -notlike "*SERVER*"} | Sort Name).Name) {
	Write-Progress -Activity "Inventorying Hardware." -Status "Checking $PC" 
# Make sure it's online and answering RPC
	If (Test-Connection $PC -Count 1 -Quiet){
		$MB = Get-WMIObject Win32_ComputerSystem -ComputerName $PC}  # Serial, Hardware from here
		If ($MB){  # meaning RPC, etc. are working...
	# do stuff...
			Get-ADComputer -Filter {LastLogonTimeStamp -lt $time} -Properties whenCreated,whenChanged, LastLogonTimeStamp, Enabled, OperatingSystem  |
			Select-Object Name,@{Name="Stamp"; Expression={[DateTime]::FromFileTime($_.lastLogonTimestamp)}}, whenCreated, whenChanged ,Enabled, OperatingSystem 
		}  # End if GWMI returned data
	}  # End if PC is online
}  # End For Each PC

You could refactor that to eliminate the extra Get-ADComputer call…

Serial Number can be had by:

Get-WmiObject win32_SystemEnclosure -ComputerName $PC).SerialNumber
Get-WmiObject Win32_Processor -ComputerName $PC

…will give you CPU, Speed, Cores, etc.

For RAM, I wanted DETAILS, so I cobbled this together which you can use to get what you want:

# RAM Installed
		"`t`t`t`tRAM"
		$RAMArray = Get-WmiObject -Class "Win32_PhysicalMemoryArray" -namespace "Root\CIMV2" -ComputerName $PC
		$AllSlots = Get-WmiObject -Class "Win32_PhysicalMemory" -namespace "Root\CIMV2" -ComputerName $PC
		"`tTotal Installed RAM: " + ((Get-WmiObject -Class "CIM_PhysicalMemory" -ComputerName $PC | 
		 Measure-Object -Property Capacity -Sum).Sum / 1GB) + " GB"
		"`tTotal Number of DIMM Slots: $($RAMArray.MemoryDevices)"
		"`n" 
		Foreach ($DIMM In $AllSlots) # Disclose info for each DIMM
			{
			"Memory Installed: `t$($DIMM.DeviceLocator)`t$($DIMM.Description)"
			"BankLabel:        `t$($DIMM.BankLabel)"
			"Memory Size:      `t$(($DIMM.Capacity / 1GB)) GB"
			"Speed:            `t$($DIMM.Speed)"
			"TotalWidth:       `t$($DIMM.TotalWidth)"
			"FormFactor:       `t$($DIMM.FormFactor)"
			"Manufacturer:     `t$($DIMM.Manufacturer)"
			if ($DIMM.Model) {"Model:            `t$($DIMM.Model)"}  ## This seems blank a lot, so why print it?
			if ($DIMM.Caption -ne $DIMM.Description) {  ## Redundant?  Thanks fer nuttin.
				"Caption:          `t$($DIMM.Caption)"}
			if ($DIMM.Name -ne $DIMM.Description) {  ## Oh, even more redundant?  Lovely.
				"Name:           `t$($DIMM.Name)"}
			"Part Number:      `t$($DIMM.PartNumber)"
			"Serial Number:    `t$($DIMM.SerialNumber)"
			if ($DIMM.Attributes) {"Attributes:    `t$($DIMM.Attributes)"}  ## Usually blank but useful if not.
			"`n"
		} # End ForEach DIMM

(You can tell I was green by the use of quoted strings to output data!)

1 Spice up