Get a list of devices with missing drivers using powershell - powershell

This is on a Windows XP pro System (yeah I know old OS)
I have been searching for a way to get a list of all devices that do not have drivers installed, or there are problems with the drivers in use.
I have tried
$foo = Get-WmiObject Win32_PNPEntity | Where-Object{$_.ConfigManagerErrorcode -ne 0}
The problem with this, is it does not seem to get all exceptions.
For instance, a HP laptop that has a finger print scanner
shows in device manager as other device - USB Device.
This was not detected using the one liner I listed.
is there a way to get an array of the missing drivers using powershell?

#For formatting:
$result = #{Expression = {$_.Name}; Label = "Device Name"},
#{Expression = {$_.ConfigManagerErrorCode} ; Label = "Status Code" }
#Checks for devices whose ConfigManagerErrorCode value is greater than 0, i.e has a problem device.
Get-WmiObject -Class Win32_PnpEntity -ComputerName localhost -Namespace Root\CIMV2 | Where-Object {$_.ConfigManagerErrorCode -gt 0 } | Format-Table $result -AutoSize
Error Codes in Windows Device Manager :- https://support.microsoft.com/en-us/kb/310123
Win32_PNP Entity Class : https://msdn.microsoft.com/en-us/library/aa394353(v=vs.85).aspx

I did this when i had some devices that where not being picked up by my script , give it a try and see if it detects your devices.
$foo = Get-WmiObject Win32_PNPEntity | Where-Object{$_.Availability -eq 11 -or $_.Availability -eq 12}

Related

Uninstall Multiple Applications in Powershell

I am trying to create a function that goes through the array $packages to uninstall multiple built in applications that come with new PCs. When running this script I am receiving an error "null-valued expression" At line 6 char 3 $app.Uninstall(). Any see where i went wrong?
foreach($package in $packages){
$app = Get-WmiObject -Class Win32_Product | Where-Object {
$_.Name -match "$package"
}
$app.Uninstall()
}

PowerShell ForEach-Object within Pipeline

I'm just learning powershell and trying to understand how looping works on ForEach Object. I was able to make this script work that detect USB Storage attached to a device
Get-CimInstance -ClassName Win32_DiskDrive |
where {$_.InterfaceType -eq 'USB'} |
ForEach-Object{"`n`n",$_ } |
Format-list -Property DeviceId,Model,Size
Output:
DeviceId : \\.\PHYSICALDRIVE1Model : WD My Passport 0740 USB DeviceSize : 1000169372160
DeviceId : \\.\PHYSICALDRIVE2Model : TOSHIBA TransMemory USB DeviceSize : 7748213760
However I'm having hardtime targeting the value of each to move it to the next line. the result should be something like this
If I ran the script in Powershell console by using format-list it display perfect however on a webpage it won't display accordingly. How can I use the backtick (`n) so that the result of DeviceID, Model and Size will be on a separate line.
I will appreciate any help. thank you guys
Please use select-object instead of For-each object
Get-CimInstance -ClassName Win32_DiskDrive | where{$.InterfaceType -eq 'USB'} |Select-object -Property DeviceId,Model,Size
#You can filter at CIM level, no need to do it at shell level, also you can specify the list of properties to retrieve
$data = Get-CimInstance -query "Select DeviceId,Model,Size from Win32_DiskDrive where InterfaceType='usb'"
#If you want a string with the format: [PropertyName]:[PropertyValue]`n[PropertyName]:[PropertyValue]...
$stringArray = #(
$data | %{
"DeviceId: $($_.DeviceId)`nModel: $($_.Model)`nSize: $($_.Size)"
}
)
Output ($stringArray):
DeviceId: \\.\PHYSICALDRIVE1
Model: Generic USB Flash Disk USB Device
Size: 15512878080
#Maybe convertto-html is of use for you?
$data | ConvertTo-Html

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.

List of all COM ports shown in device manager by using PowerShell

I want to incorporate a dropdown menu that is populated with the list of available COM ports. I can't find any way to easily get the names of the available COM ports to put in the place of COM4 that creates the $port.
$port = new-Object System.IO.Ports.SerialPort COM4,19200,None,8,one
By using Win32_SerialPort I am able to easily extract COM1 and COM3.
Get-WmiObject Win32_SerialPort | Select-Object deviceid
Results:
deviceid
COM3
COM1
But my device manager shows 16 available ports from a remote serial hub.
Device Manager Snapshot
Here is what I have tried and I am able to narrow down the Name, but can't figure out how to extract just the (COM--) part.
Get-WmiObject Win32_pnpentity -Filter "Name LIKE 'devicemaster port%'" | Select-Object -Property Name
Result Screenshot
Adding a late answer because I just had a need for this...
You can use WMI ClassGuids to get the exact list (COM and LPT) that device manager shows:
$lptAndCom = '{4d36e978-e325-11ce-bfc1-08002be10318}'
get-wmiobject -Class win32_pnpentity | where ClassGuid -eq $lptAndCom | select name
Confirmed to work with a few LPT / COM extension cards (Brain Boxes / Exar), using Windows 8.1 up to server 2019 (Powershell 4 onwards).
The full list of ClassGuids is here:
https://learn.microsoft.com/en-us/windows-hardware/drivers/install/system-defined-device-setup-classes-available-to-vendors
Here is a more up-to-date solution to get the COM-port details:
cls
$portList = get-pnpdevice -class Ports -ea 0
$portCount = 0
if ($portList) {
$now = get-date
foreach($device in $portList) {
$id = $device.InstanceId
if ($device.Present) {
$date = $now
} else {
$info = Get-PnpDeviceProperty -InstanceId $id
$latest = $info | ?{$_.KeyName -eq "DEVPKEY_Device_LastRemovalDate"}
$date = [datetime]$latest.Data
}
$age = $now-$date
if ($age.Days -lt 14) {
"port name : $name"
"last active: $date"
""
$portCount++
}
}
}
"number of active COM-port devices in last 14 days: $portCount"
Leaving some work to you to figure out, but based on your Result Screenshot you can do something like this:
$ports = #()
$ports += 'devicemaster port (COM1)'
$ports += 'devicemaster port (COM2)'
$ports += 'devicemaster port (COM3)'
$ports += 'devicemaster port (COM4)'
$ports | % {
if ($_ -match "devicemaster port \((.*)\)") {
$matches[1]
}
}
with that object, assuming you store that in '$ports'. You may need to use '$ports.Name'...
Possibly see regex101.com for how the regex works.

Powershell - Bytes sent/received

I need to create a script that samples the network traffic every 30 seconds and stores the bytes sent/received. This data is then later used to draw graphs. I wrote one that works perfectly on Windows 2012 but i realised some of the cmdlets were not available in previous versions like 2008 so i am seeking alternatives.
For windows 2012 i used get-netadapterstatistics to get the received/sent bytes but this won't work on pre 2012 so i thought i could use netstat -e but the problem is both are giving me completely different results and i was hoping someone can tell me why? The script below was written to see the different between data.
function getNic{
$nic = Get-NetRoute | ? DestinationPrefix -eq '0.0.0.0/0' | Get-NetIPInterface | Where ConnectionState -eq "Connected" | Select -ExpandProperty InterfaceAlias
return $nic
}
function getBR{
$b = ((netstat -e | Select-String "Bytes") -split '\s+')[2]
$a = (Get-NetAdapterStatistics |Where InterfaceAlias -eq $nic_name |Select -ExpandProperty SentBytes)
$a - $script:startbr
$b - $script:startbr2
$script:startbr = $a
$script:Startbr2 = $b
}
$nic_name = getNic
$startbr = (Get-NetAdapterStatistics |Where InterfaceAlias -eq $nic_name |Select -ExpandProperty SentBytes)
$startbr2 = ((netstat -e | Select-String "Bytes") -split '\s+')[2]
for(1..1000){
getBR
Start-Sleep 5
}
The results are as below
0
0
4577
18308
6695
26780
9055
36220
Ideally i am only interested in capturing traffic on the external interface.
While i can´t offer you an explanation for the difference between your methods i could offer you an alternative that should work on pre 2012 as well as on 2012 upwards:
$ifIndex = Get-WmiObject -Class win32_ip4routetable | where {$_.destination -eq "0.0.0.0"} | select -ExpandProperty InterfaceIndex
$ifIndex = "InterfaceIndex=" + $ifIndex
$nic_name = Get-WmiObject -Class win32_networkadapterconfiguration -Filter $ifIndex | select -ExpandProperty Description
$nic = [System.Net.NetworkInformation.Networkinterface]::GetAllNetworkInterfaces() | where {($_.description -eq $nic_name) -and ($_.operationalstatus -eq "up")}
$stats = $nic.GetIPv4Statistics()
$bytesSent = $stats.BytesSent
$bytesReceived = $stats.BytesReceived
This gives results consistent with the Get-NetAdapterStatistics Cmdlet on my system
After thinking about it maybe netstat shows statistics for multiple network adapters (maybe including loopback) combined since there is no differentiation by nic? Just guessing but this might explain the increased bytecount. Sadly there´s no details to be found in the docs