Powershell Script to Gather PC hardware details from existing Computers - powershell

Hi All,
I was hoping if someone has done this scenario before. I'm looking for a PowerShell script to gather PC Hardware details in the local network. it's Windows 7,10 and not in DC.
Details I would like to get from each PC is
RAM (name and size)
CPU (name and size)
HDD (name and size)
Local User profiles
Is it something possible (logically I can't see how it's possible) as PC's are not in a domain.
Any suggestions would helpful
Love & Peace
My fellow humans

This should do the trick:
Add-Type -AssemblyName System.Collections
[System.Collections.Generic.List[string]]$hdd = #()
$system = Get-CimInstance CIM_ComputerSystem
$cpu = Get-CimInstance CIM_Processor
$users = Get-WmiObject -ComputerName "localhost" -Class Win32_UserAccount -Filter "LocalAccount='True'" |Select PSComputername, Name, Status, Disabled, AccountType, Lockout, PasswordRequired, PasswordChangeable, SID
$driveLetter = 'C'
$currentHdd = Get-CimInstance Win32_LogicalDisk -Filter "DeviceID = '$($driveletter):'"
while( $currentHdd.DeviceID ) {
switch( $currentHdd.DriveType ) {
3 {
$driveType = "HDD"
break;
}
5 {
$driveType = "Optical"
break;
}
default {
$driveType = "Other"
}
}
$drive = $driveletter + ': ' + $driveType + (" {0:N2}" -f ($currentHdd.Size/1GB) + " GB ") + ("{0:N2}" -f ($currentHdd.FreeSpace/1GB) + " GB ")
$hdd.Add( $drive )
$driveLetter = ([char](++([byte]([char]$driveLetter)))).ToString()
$currentHdd = Get-CimInstance Win32_LogicalDisk -Filter "DeviceID = '$($driveletter):'"
}
$ram = "{0:N2}" -f ($system.TotalPhysicalMemory/1GB) + " GB"
$cpuName = $cpu.Name
"CPU: $cpuName"
"RAM: $ram"
"Disks:"
$hdd
"Users:"
$users

This will do the trick for machines NOT on domain.
You will need:
IP Address(s)
Admin login credentials for the remote machine
Below syntax will query Windows7-Windows10 machines for RAM, CPU, HDD and User profiles:
wmic /NODE:"127.0.0.1" memorychip get capacity & wmic /NODE:"127.0.0.1" cpu list brief & wmic /NODE:"127.0.0.1" diskdrive get Name, Manufacturer, Model & wmic /NODE:"127.0.0.1" useraccount get name
For the example above, I'm simply using loopback IP (queries the local PC you are on), but you can substitute any IP address.
You can also specify your credentials to the wmic tool if needed. Learn more about wmic here:
https://learn.microsoft.com/en-us/windows/win32/wmisdk/wmic

Related

PowerShell interrogate a remote system

I have a function that I wrote that interrogates my local system. Just gathering whatever information I can get in a useful format. So I was wondering about a function that could interrogate other systems in this kind of way. function sys-remote <$ip-or-hostname> With that it could then try and return as much information about that system as it can. It's just an idea really, and I guess a number of points would be useful:
• With an IP address, how can we resolve the hostname in the most PowerShell'ish way?
• Whether a hostname of IP address is provided, can we resolve as much information as possible. i.e. MAC address, hostname, IP (and possibly other IP addresses if these can be visible to us)?
• Can we recover shared drives on that system so can see a list of possible shares to connect to.
• What about system information, would that always require WinRM, or can WMI or CIM suffice for most of the things in the below?
• Maybe return also a comma-separate list of whatever ports are open on that remote system if possible?
• What if the remote system is Linux. How much of the above can we reasonably obtain from a Linux system that we interrogate remotely from our Windows system (I guess that WinRM and WMI are out, but maybe CIM is still possible?)?
In general, it would be really useful to return a dump of information like this from a diagnostic point of view as would give a ton of information about a system to work from. Anything like the above (or indeed any other useful things to check for that I've not thought of here) would be really appreciated.
function sys {
$System = get-wmiobject -class "Win32_ComputerSystem"
$Mem = [math]::Ceiling($System.TotalPhysicalMemory / 1024 / 1024 / 1024)
$wmi = gwmi -class Win32_OperatingSystem -computer "."
$LBTime = $wmi.ConvertToDateTime($wmi.Lastbootuptime)
[TimeSpan]$uptime = New-TimeSpan $LBTime $(get-date)
$s = "" ; if ($uptime.Days -ne 1) {$s = "s"}
$uptime_string = "$($uptime.days) day$s $($uptime.hours) hr $($uptime.minutes) min $($uptime.seconds) sec"
$job_cpu = Start-Job -ScriptBlock { (Get-WmiObject -Class Win32_Processor).Name }
$job_cpu_cores = Start-Job -ScriptBlock { (Get-WmiObject -Class Win32_Processor).NumberOfCores }
$job_cpu_logical = Start-Job -ScriptBlock { (Get-WmiObject -Class Win32_Processor).NumberOfLogicalProcessors }
""
"Hostname: $($System.Name)"
"Domain: $($System.Domain)"
"PrimaryOwner: $($System.PrimaryOwnerName)"
"Make/Model: $($System.Manufacturer) ($($System.Model))" # "ComputerModel: $((Get-WmiObject -Class:Win32_ComputerSystem).Model)"
"SerialNumber: $((Get-WmiObject -Class:Win32_BIOS).SerialNumber)"
"PowerShell: $($PSVersionTable.PSVersion)"
"Windows Version: $($PSVersionTable.BuildVersion), Windows ReleaseId: $((Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name 'ReleaseId').ReleaseId)"
"Display Card: $((Get-WmiObject -Class:Win32_VideoController).Name)"
"Display Driver: $((Get-WmiObject -Class:Win32_VideoController).DriverVersion), Description: $((Get-WmiObject -Class:Win32_VideoController).VideoModeDescription)"
"Last Boot Time: $([Management.ManagementDateTimeConverter]::ToDateTime((Get-WmiObject Win32_OperatingSystem | select 'LastBootUpTime').LastBootUpTime)), Uptime: $uptime_string"
$IPDefaultAddress = #(Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object {$_.DefaultIpGateway})[0].IPAddress[0]
$IPDefaultGateway = #(Get-WmiObject Win32_NetworkAdapterConfiguration | Where-Object {$_.DefaultIpGateway})[0].DefaultIPGateway[0]
"Default IP: $IPDefaultAddress / $IPDefaultGateway"
Get-Netipaddress | where AddressFamily -eq IPv4 | select IPAddress,InterfaceIndex,InterfaceAlias | sort InterfaceIndex
""
Wait-Job $job_cpu | Out-Null ; $job_cpu_out = Receive-Job -Job $job_cpu
Wait-Job $job_cpu_cores | Out-Null ; $job_cpu_cores_out = Receive-Job -Job $job_cpu_cores
Wait-Job $job_cpu_logical | Out-Null ; $job_cpu_logical_out = Receive-Job -Job $job_cpu_logical
"CPU: $job_cpu_out"
"CPU Cores: $job_cpu_cores_out, CPU Logical Cores: $job_cpu_logical_out"
# Get-PSDrive | sort -Descending Free | Format-Table
gwmi win32_logicaldisk | Format-Table DeviceId, VolumeName, #{n="Size(GB)";e={[math]::Round($_.Size/1GB,2)}},#{n="Free(GB)";e={[math]::Round($_.FreeSpace/1GB,2)}}
gwmi win32_winsat | select-object CPUScore,D3DScore,DiskScore,GraphicsScore,MemoryScore,WinSPRLevel | ft # removed ,WinSATAssessmentState
get-WmiObject -class Win32_Share | ft
}
No reason to do this sort of thing from scratch. There are many existing scripts for what you are doing. Via the Microsoft powershellgallery.com.
PowerShell Script For Desktop Inventory Basic script to collect
desktop inventory.
PowerShell Hardware Inventory Script Scenario:PowerShell hardware
Inventory Script. Have you ever wanted to have an inventory without the
hassle of going to each finding the information needed to fill the
information for your inventory? It is important to keep your inventory
up to date. Every time there is a change y
DownloadGet-Inventory.ps1
You can just take your script and use Invoke-Command (Runs commands on local and remote computers.) in a PowerShell remote session to get remote computer info.

powershell get info about computer

I'm trying to create a powershell script (getting more advanced... JK. Powershell offers more features than the batch file, and I want to use some of them.)
So, here's my batch script:
:Start
#echo off
set /p password="Password:"
:Nextcomp
set /p computer="Computer name:"
wmic /user:username /password:%password% /node:"%computer%" memorychip get capacity
set /P c=Do you want to get info about another computer (y/n)?
if /I "%c%" EQU "y" goto :Nextcomp
if /I "%c%" EQU "n" goto :End goto :choice
pause
:End
And here's what I found: Script
I modified it for my needs, but whenever I try to run this script, I get it the wrong way - it's displaying me the entire script, and only in the end is it asking me about the computer name:
$resultstxt = "C:\Users\user\Documents\results.csv"
Param(
[Parameter(Mandatory=$true, Position=0, HelpMessage="Password?")]
[SecureString]$password
)
$pw = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($password))
$Computer = Read-Host -Prompt 'Computer name'
$out = #()
If (!(Test-Connection -ComputerName $Computer -Count 1 -Quiet)) {
Write-Host "$Computer not on network."
Continue
}
foreach($object in $HostList) {
$RAM = get-wmiobject -user user -password $pw -computername $object.("Computer")-class win32_physicalmemory
$DeviceInfo= #{}
$DeviceInfo.add("RAM", "$([math]::floor($RAM.Capacity/ (1024 * 1024 * 1024 )) )" + " GB" )
$DeviceInfo.add("Computer Name", $vol.SystemName)
$out += New-Object PSObject -Property $DeviceInfo | Select-Object "RAM"
Write-Verbose ($out | Out-String) -Verbose
$out | Export-CSV -FilePath $resultstxt -NoTypeInformation
}
As you might have guessed, I have a lot more fields, but they all are similar, and I borrowed from a lot of sources, but mainly from the "Script" link.
What I want is:
Hide the password
Export the information to CSV, with each new computer (see 3.) added following the current computer (on the next line)
Ask if I want to get the info about another computer, with "y" key for yes, "n" for no.
Make the script work
I found about the problem 1, but I haven't tested it yet, so... will it work? Next, I found about problem 2, but it would display all info in a not-easy-to-read format, and not everything I need, and all in one cell. Finally, about 3, I found, but it wouldn't work. I can't say I dug the entire Internet, but I'm hoping you guys (and gals?) can help me figure it out. It shouldn't be that hard to resolve these 3 issues, it's not a super complicated script after all, right? My current script is only 31 lines, including the whitespaces.
this is a demo of one way to get basic system info from a group of systems. it uses the CIM cmdlets since they are faster than the WMI cmdlets [most of the time], present datetime info as standard datetime objects, AND not somewhat deprecated.
it also uses the Invoke-Command cmdlet for remote parallelism, and is set to ignore errors so that non-responding systems don't waste your time.
#requires -RunAsAdministrator
# fake reading in a list of computer names
# in real life, use Get-Content or (Get-ADComputer).Name
$ComputerList = #'
Localhost
BetterNotBeThere
127.0.0.1
10.0.0.1
::1
'# -split [environment]::NewLine
$IC_ScriptBlock = {
$CIM_ComputerSystem = Get-CimInstance -ClassName CIM_ComputerSystem
$CIM_BIOSElement = Get-CimInstance -ClassName CIM_BIOSElement
$CIM_OperatingSystem = Get-CimInstance -ClassName CIM_OperatingSystem
$CIM_Processor = Get-CimInstance -ClassName CIM_Processor
$CIM_LogicalDisk = Get-CimInstance -ClassName CIM_LogicalDisk |
Where-Object {$_.Name -eq $CIM_OperatingSystem.SystemDrive}
[PSCustomObject]#{
LocalComputerName = $env:COMPUTERNAME
Manufacturer = $CIM_ComputerSystem.Manufacturer
Model = $CIM_ComputerSystem.Model
SerialNumber = $CIM_BIOSElement.SerialNumber
CPU = $CIM_Processor.Name
SysDrive_Capacity_GB = '{0:N2}' -f ($CIM_LogicalDisk.Size / 1GB)
SysDrive_FreeSpace_GB ='{0:N2}' -f ($CIM_LogicalDisk.FreeSpace / 1GB)
SysDrive_FreeSpace_Pct = '{0:N0}' -f ($CIM_LogicalDisk.FreeSpace / $CIM_LogicalDisk.Size * 100)
RAM_GB = '{0:N2}' -f ($CIM_ComputerSystem.TotalPhysicalMemory / 1GB)
OperatingSystem_Name = $CIM_OperatingSystem.Caption
OperatingSystem_Version = $CIM_OperatingSystem.Version
OperatingSystem_BuildNumber = $CIM_OperatingSystem.BuildNumber
OperatingSystem_ServicePack = $CIM_OperatingSystem.ServicePackMajorVersion
CurrentUser = $CIM_ComputerSystem.UserName
LastBootUpTime = $CIM_OperatingSystem.LastBootUpTime
}
}
$IC_Params = #{
ComputerName = $ComputerList
ScriptBlock = $IC_ScriptBlock
ErrorAction = 'SilentlyContinue'
}
$RespondingSystems = Invoke-Command #IC_Params
$NOT_RespondingSystems = $ComputerList.Where({
# these two variants are needed to deal with an ipv6 localhost address
"[$_]" -notin $RespondingSystems.PSComputerName -and
$_ -notin $RespondingSystems.PSComputerName
})
# if you want to remove the PSShowComputerName, PSComputerName & RunspaceID props, use ...
# Select-Object -Property * -ExcludeProperty PSShowComputerName, PSComputerName, RunspaceId
'=' * 40
$RespondingSystems
'=' * 40
$NOT_RespondingSystems
truncated output ...
LocalComputerName : [MySysName]
Manufacturer : System manufacturer
Model : System Product Name
SerialNumber : System Serial Number
CPU : AMD Phenom(tm) II X4 945 Processor
SysDrive_Capacity_GB : 931.41
SysDrive_FreeSpace_GB : 745.69
SysDrive_FreeSpace_Pct : 80
RAM_GB : 8.00
OperatingSystem_Name : Microsoft Windows 7 Professional
OperatingSystem_Version : 6.1.7601
OperatingSystem_BuildNumber : 7601
OperatingSystem_ServicePack : 1
CurrentUser : [MySysName]\[MyUserName]
LastBootUpTime : 2019-01-24 1:49:31 PM
PSComputerName : [::1]
RunspaceId : c1b949ef-93af-478a-b2cf-e44d874c5724
========================================
BetterNotBeThere
10.0.0.1
to get a well structured CSV file, send the $RespondingSystems collection to the file via Export-CSV.
for a demo of a loop to wrap around any given block of code, take a look at this ...
$Choice = ''
while ([string]::IsNullOrEmpty($Choice))
{
$Choice = Read-Host 'Please enter a valid computer name or [x] to exit '
# replace below with real code to check if $ComputerName is valid
if ($Choice -eq $env:COMPUTERNAME)
{
$ValidCN = $True
}
else
{
$ValidCN = $False
}
if (-not $ValidCN -and $Choice -ne 'x')
{
# insert desired error notice
[console]::Beep(1000, 300)
Write-Warning ''
Write-Warning ('Your choice [ {0} ] is not a valid computer name.' -f $Choice)
Write-Warning ' Please try again ...'
pause
$Choice = ''
}
elseif ($Choice -ne 'x')
{
# insert code to do the "ThingToBeDone"
Write-Host ''
Write-Host ('Doing the _!_ThingToBeDone_!_ to system [ {0} ] ...' -f $Choice)
pause
$Choice = ''
}
}
on screen output ...
Please enter a valid computer name or [x] to exit : e
WARNING:
WARNING: Your choice [ e ] is not a valid computer name.
WARNING: Please try again ...
Press Enter to continue...:
Please enter a valid computer name or [x] to exit : [MySysName]
Doing the _!_ThingToBeDone_!_ to system [ [MySysName] ] ...
Press Enter to continue...:
Please enter a valid computer name or [x] to exit : x

PowerShell :: How to filter worker processes list by User Name

Basically as per screen-shot there are multiple worker processes are running on machine in IIS but we need w3wp which is running under Sitecore User Username.
We tried below PS script but getting blank value in User Name column
$processlist = get-process | where {$_.cpu -gt 5 -and $_.Name -eq 'w3wp'} |select Name, #{l="User name";e={$_.getowner().user}} | ft -AutoSize
foreach($proc in $processlist){
if($proc -eq "Sitecore User" ){
C:\Users\Administrator\Documents\someexe.exe $proc.Id "C:\Users\Administrator\Documents\output.dmp"
}
}
and finally we need to perform some action on process Id.
I suggest the following PoSh-Script that should give you all the necessary info and more:
# Ensure to import the WebAdministration module
Import-Module WebAdministration
# Declare the variables
$server = "localhost"
$search = "*"
$wmiQuery=[wmisearcher]"SELECT * FROM __Namespace where NAME like 'WebAdministration' or NAME like 'MicrosoftIISv2'"
$wmiQuery.Scope.Path = "\\" + $server + "\root"
$WebNamespace = $wmiQuery.Get()
# Checking if the the server has IIS installed
if($WebNamespace -like '*WebAdministration*')
{
"IIS found on $server"
$WPlist=Get-WmiObject -NameSpace 'root\WebAdministration' -class 'WorkerProcess' -ComputerName 'LocalHost'
# Loop through the list of active IIS Worker Processes w3wp.exe and fetch the PID, AppPool Name and the startTime
forEach ($WP in $WPlist)
{
if ($WP.apppoolname -like$search)
{
write-host "Found:""PID:"$WP.processid "AppPool_Name:"$WP.apppoolname
(get-process -ID $WP.processid|select starttime)
}
}
}
Else
{
write-host"WARNING: IIS not detected."
}
Ref: https://blogs.msdn.microsoft.com/webtopics/2015/11/28/query-the-active-worker-process-information-in-iis-7-x-using-powershell/

Remove Symantec Endpoint Protection in an Enterprise Environment

I have many servers I need to remove Symantec Endpoint Protection from. I contacted Symantec and received the code below:
(Get-WmiObject -Class Win32_Product -Filter "Name='Symantec Endpoint Protection'" -ComputerName xxxxxx).Uninstall()
I have used it and it worked on 10 servers no problem at all. I tried it again today and am getting the error:
You cannot call a method on a null-valued expression.
At line:1 char:1
+ (Get-WmiObject -Class Win32_Product -Filter "Name='Symantec Endpoint Protection' ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull
Nothing has changed from when I started and am trying to figure out what the above error means. Also if I can get this to work does anyone see a way to add many servers to a foreach command or something.
Two things from my side:
1) you should not use win32_product cause it is broken to a certain level.
It is very slow alsso because it scans the entire thing.
2) In your case, "Name='Symantec Endpoint Protection'" reports Null for you which means that the value is not there. Please check the proper name.
For better performance and as part of enhancement , you should use the registry to fetch the details.
Function Get-RemoteSoftware{
<#
.SYNOPSIS
Displays all software listed in the registry on a given computer.
.DESCRIPTION
Uses the SOFTWARE registry keys (both 32 and 64bit) to list the name, version, vendor, and uninstall string for each software entry on a given computer.
.EXAMPLE
C:\PS> Get-RemoteSoftware -ComputerName SERVER1
This shows the software installed on SERVER1.
#>
param (
[Parameter(mandatory=$true,ValueFromPipelineByPropertyName=$true)][string[]]
# Specifies the computer name to connect to
$ComputerName
)
Process {
foreach ($Computer in $ComputerName)
{
#Open Remote Base
$reg=[microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine',$Computer)
#Check if it's got 64bit regkeys
$keyRootSoftware = $reg.OpenSubKey("SOFTWARE")
[bool]$is64 = ($keyRootSoftware.GetSubKeyNames() | ? {$_ -eq 'WOW6432Node'} | Measure-Object).Count
$keyRootSoftware.Close()
#Get all of they keys into a list
$softwareKeys = #()
if ($is64){
$pathUninstall64 = "SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
$keyUninstall64 = $reg.OpenSubKey($pathUninstall64)
$keyUninstall64.GetSubKeyNames() | % {
$softwareKeys += $pathUninstall64 + "\\" + $_
}
$keyUninstall64.Close()
}
$pathUninstall32 = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
$keyUninstall32 = $reg.OpenSubKey($pathUninstall32)
$keyUninstall32.GetSubKeyNames() | % {
$softwareKeys += $pathUninstall32 + "\\" + $_
}
$keyUninstall32.Close()
#Get information from all the keys
$softwareKeys | % {
$subkey=$reg.OpenSubKey($_)
if ($subkey.GetValue("DisplayName")){
$installDate = $null
if ($subkey.GetValue("InstallDate") -match "/"){
$installDate = Get-Date $subkey.GetValue("InstallDate")
}
elseif ($subkey.GetValue("InstallDate").length -eq 8){
$installDate = Get-Date $subkey.GetValue("InstallDate").Insert(6,".").Insert(4,".")
}
New-Object PSObject -Property #{
ComputerName = $Computer
Name = $subkey.GetValue("DisplayName")
Version = $subKey.GetValue("DisplayVersion")
Vendor = $subkey.GetValue("Publisher")
UninstallString = $subkey.GetValue("UninstallString")
InstallDate = $installDate
}
}
$subkey.Close()
}
$reg.Close()
}
}
}
Note: Use the function or the query inside the function to get the result.
Hope it helps.

Get-WmiObject: Only select local (to the current session) objects?

I have Powershell code like this:
$disks = Get-WmiObject -Class Win32_MappedLogicalDisk -Filter "DeviceID='Z:'"
foreach($disk in $disks)
{
[Console]::WriteLine("Object: " + $disk.Name + " is " + $disk.ProviderName );
}
But it selects objects outside of the current session, like other users on the terminal session. How can I limit this to objects only under the current session?
You can use this:
gwmi Win32_LogicalDisk -Filter "DeviceID='Z:' " | ? { $_.drivetype -eq 4 }
the where condition it's only to be sure is a network drive and not other kind of unit.
You can read here other drivetype code