Monitor Serial Numbers of Remote Machines from Text File

This topic contains 13 replies, has 5 voices, and was last updated by  Naw Awn 2 days, 1 hour ago.

  • Author
    Posts
  • #81896

    IT_Support
    Participant

    Hi All,
    Sorry, though completely new to powershell and trying to learn for the first time this week but really lost and have very short deadline to obtain,so hoping someone can help so i dont have to manually walk and scan each monitor.

    I want to scan a list of machines (text file I) that I got from a DSquery and display their Make/Model/Serial number along side of the Hostname of the machine, and the 2 last logged in users of the machine.
    Any help or advice would be greatly appreciated. I need in similar format as the most i would have is 4 monitors connected and will then use this data to input into other systems. Thanks

    PS C:\Scripts\> Get-Monitor -ComputerName $Computers

    PC Name / PC Model / PC Serial Number / L.Logged In User 1 / L.Logged in User 2 /Monitor Make Model/ Monitor SN /
    ———— —– ———— —————-
    PC1SYD1234 DEL 7500 XXXXX mrX, Mrs Y HP HP LA2405x CN12345678 SSL7-F108F-9D4Z
    PC1SYD1234 DEL 7500 XXXXX mrX, Mrs Y HP HP LA2405x CN12345679 SSL7-F108F-9D4Z
    PC1SYD1234 DEL 7500 XXXXX mrX, Mrs Y HP HP LA2405x CN123456710 SSL7-F108F-9D4Z

    PC2SYD1235 DEL 7500 XXXXX mrX, Mrs Y HP HP LA2405x CN123456710 SSL7-F108F-9D4Z
    PC2SYD1235 DEL 7500 XXXXX mrX, Mrs Y HP HP LA2405x CN123456710 SSL7-F108F-9D4Z

    I need to make sure it caters for Dell Monitors that apparently have issues with scripts from what I've read, so may need to some how incorporate:
    function Decode {
    If ($args[0] -is [System.Array]) {
    [System.Text.Encoding]::ASCII.GetString($args[0])
    }
    Else {
    "Not Found"
    }
    }

    echo "Name, Serial"

    ForEach ($Monitor in Get-WmiObject WmiMonitorID -Namespace root\wmi) {
    $Name = Decode $Monitor.UserFriendlyName -notmatch 0
    $Serial = Decode $Monitor.SerialNumberID -notmatch 0

    echo "$Name, $Serial"
    }

  • #81907

    Jeremy Murrah
    Participant

    Not sure how much you already have written, but since you mention using a "get-monitor" command I'm assuming that's a function you've started writing. If not, here is what you might use to start.

    function Get-Monitor {
        Param(
            [String[]]$Computername
        )
        Foreach ($Computer in $Computername){
    
        }
    }
    

    You can pass your list of computers to that function, which will then loop through each one of them and do stuff. In this case it sounds like you just need to do a few WMI (or CIM) queries. So maybe something like this:

    function Get-Monitor {
        Param(
            [String[]]$Computername
        )
        Foreach ($Computer in $Computername){
            $ComputerSystemInfo = Get-WmiObject -Class win32_computersystem -ComputerName $computer
            $MonitorInfo = Get-WmiObject -Namespace root\wmi -Class WmiMonitorID -ComputerName $computer
            $BIOSInfo = Get-WmiObject -Class win32_bios -ComputerName $computer
        }
    }
    

    That gets all the info into memory, probably more than you are actually looking for. The last thing to do then is to just create an output object to cherry pick the specific items you want in your output.

    function Get-Monitor {
        Param(
            [String[]]$Computername
        )
        Foreach ($Computer in $Computername){
            $ComputerSystemInfo = Get-WmiObject -Class win32_computersystem -ComputerName $computer
            $MonitorInfo = Get-WmiObject -Namespace root\wmi -Class WmiMonitorID -ComputerName $computer
            $BIOSInfo = Get-WmiObject -Class win32_bios -ComputerName $computer
    
            $output = New-Object PSObject -Property @{
                'Name' = $ComputerSystemInfo.Name
                'Model' = $ComputerSystemInfo.Model
                'SerialNumber' = $BIOSInfo.SerialNumber
                'LoggedOnUser' = $ComputerSystemInfo.UserName
            }
        }
    }
    

    I left out the monitor stuff since that's not a strict one to one mapping. You could have one or more monitors, so I'd probably use add-member to append those.

    function Get-Monitor {
        Param(
            [String[]]$Computername
        )
        Foreach ($Computer in $Computername){
            $ComputerSystemInfo = Get-WmiObject -Class win32_computersystem -ComputerName $computer
            $MonitorInfo = Get-WmiObject -Namespace root\wmi -Class WmiMonitorID -ComputerName $computer
            $BIOSInfo = Get-WmiObject -Class win32_bios -ComputerName $computer
    
            $output = New-Object PSObject -Property @{
                'Name' = $ComputerSystemInfo.Name
                'Model' = $ComputerSystemInfo.Model
                'SerialNumber' = $BIOSInfo.SerialNumber
                'LoggedOnUser' = $ComputerSystemInfo.UserName
            }
            for ($i = 0; $i -lt $MonitorInfo.Length; $i++){ 
                $output | add-member -MemberType NoteProperty -Name "Monitor$i`Name" -Value $([system.text.encoding]::ascii.GetString($($MonitorInfo[0].ManufacturerName)))
                $output | Add-Member -MemberType NoteProperty -name "Monitor$i`Serial#" -Value $([system.text.encoding]::ascii.GetString($($MonitorInfo[0].SerialNumberid)))
            }
            $output
        }
    }
    
  • #81919

    Aaron Hardy
    Participant

    Not to dampen the project but keep in mind when getting serial numbers from the monitors, the values 'burned' in the monitor itself can be different than what the outside or packaging shows; a lot of times it's a shortened version of the full serial number.

    The internal value depends on how the manufacturer has entered it, and unfortunately with many of them, they don't always match (based on my experience). However, the script can still be useful as some will work.

    • #81935

      IT_Support
      Participant

      Thanks guys,
      Much appreciated for the prompt response.
      Unfortunately I hadn't written much so far as powershell is virtually brand new to me,
      I had played around with vbscript many years ago and read several forums warning of especially Dell using different Serial numbers than what is on the sticker and apparently the need to search for "Friendly Names/Numbers".
      I'll have a go at the above when i get to work.
      Enjoy your Day/Weekend and Thanks again.

  • #82082

    IT_Support
    Participant

    Sorry if this sounds silly, but when looking at this in Powershell ISE, I am getting errors,
    One of them being "Missing Expression after =... Not too sure why as I'm pretty sure I have used other scripts with similar format.
    SideQuestion, anyone in Epping Area Sydney that would be interested in some Tutoring lessons on PowerShell, paid of course?
    Just so I can get the basics downpacked and not have to disturb others so often.

    function Get-Monitor {
    Param(
    [String[]]$Computernames = get-content "c:\scripts\machinelist.txt"
    )
    Foreach ($Computer in $Computernames){
    $ComputerSystemInfo = Get-WmiObject -Class win32_computersystem -ComputerNames $computer
    $MonitorInfo = Get-WmiObject -Namespace root\wmi -Class WmiMonitorID -ComputerNames $computer
    $BIOSInfo = Get-WmiObject -Class win32_bios -ComputerNames $computer

    $output = New-Object PSObject -Property @{
    'Name' = $ComputerSystemInfo.Name
    'Model' = $ComputerSystemInfo.Model
    'SerialNumber' = $BIOSInfo.SerialNumber
    'LoggedOnUser' = $ComputerSystemInfo.UserName
    }
    for ($i = 0; $i -lt $MonitorInfo.Length; $i++){
    $output | add-member -MemberType NoteProperty -Name "Monitor$i`Name" -Value $([system.text.encoding]::ascii.GetString($($MonitorInfo[0].ManufacturerName)))
    $output | Add-Member -MemberType NoteProperty -name "Monitor$i`Serial#" -Value $([system.text.encoding]::ascii.GetString($($MonitorInfo[0].SerialNumberid)))
    }
    $output
    }
    }

  • #82087

    IT_Support
    Participant

    Update,, Overcome the first error, but now getting a heap of others and only partial results:
    Any ideas?

    function Get-Monitor {}
    Param(
    [String[]]$Computernames = get-content "c:\scripts\machinelist.txt"
    )
    Foreach ($Computer in $Computernames){
    $ComputerSystemInfo = Get-WmiObject -Class win32_computersystem -ComputerNames $computer
    $MonitorInfo = Get-WmiObject -Namespace root\wmi -Class WmiMonitorID -ComputerNames $computer
    $BIOSInfo = Get-WmiObject -Class win32_bios -ComputerNames $computer

    $output = New-Object PSObject -Property @{
    'Name' = $ComputerSystemInfo.Name
    'Model' = $ComputerSystemInfo.Model
    'SerialNumber' = $BIOSInfo.SerialNumber
    'LoggedOnUser' = $ComputerSystemInfo.UserName
    }
    for ($i = 0; $i -lt $MonitorInfo.Length; $i++){
    $output | add-member -MemberType NoteProperty -Name "Monitor$i`Name" -Value $([system.text.encoding]::ascii.GetString($($MonitorInfo[0].ManufacturerName)))
    $output | Add-Member -MemberType NoteProperty -name "Monitor$i`Serial#" -Value $([system.text.encoding]::ascii.GetString($($MonitorInfo[0].SerialNumberid)))
    }
    $output
    }

  • #82090

    IT_Support
    Participant

    Sorry for the floods, but I think I have almost figured it out, though I get an error about PARAM not being correct,
    however when I ctrl f and search for param, nothing found,
    function Get-Monitor {}
    Param(
    [String[]]$Computernames = get-content "c:\scripts\machinelist.txt"
    )
    Foreach ($Computer in $Computernames){
    $ComputerSystemInfo = Get-WmiObject -Class win32_computersystem -Computer $Computer
    $MonitorInfo = Get-WmiObject -Namespace root\wmi -Class WmiMonitorID -Computer $Computer
    $BIOSInfo = Get-WmiObject -Class win32_bios -Computer $Computer

    $output = New-Object PSObject -Property @{
    'Name' = $ComputerSystemInfo.Name
    'Model' = $ComputerSystemInfo.Model
    'SerialNumber' = $BIOSInfo.SerialNumber
    'LoggedOnUser' = $ComputerSystemInfo.UserName
    }
    for ($i = 0; $i -lt $MonitorInfo.Length; $i++){
    $output | add-member -MemberType NoteProperty -Name "Monitor$i`Name" -Value $([system.text.encoding]::ascii.GetString($($MonitorInfo[0].ManufacturerName)))
    $output | Add-Member -MemberType NoteProperty -name "Monitor$i`Serial#" -Value $([system.text.encoding]::ascii.GetString($($MonitorInfo[0].SerialNumberid)))
    }
    $output
    }

  • #82096

    Pradeep Arora
    Participant

    -ComputerName not -Computer, the error message will show you the line no with problem.
    Get-Help Get-WmiObject -Examples will show you some examples

  • #82097

    IT_Support
    Participant

    Thanks mate,
    I modified, now getting the below:
    In the meantime, ill look up the examples.
    ——
    PS C:\Scripts> C:\Scripts\MonitorScan.ps1
    Param : The term 'Param' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was
    included, verify that the path is correct and try again.
    At C:\Scripts\MonitorScan.ps1:2 char:5
    + Param(
    + ~~~~~
    + CategoryInfo : ObjectNotFound: (Param:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

    SerialNumber LoggedOnUser Name Model
    ———— ———— —- —–
    R89ARPG T410\Admin T410 2537MD4
    ———————–

  • #82100

    Pradeep Arora
    Participant

    function Get-Monitor {} should be function Get-Monitor {, the matching block ending } goes at the bottom of file.

    I recommend that you watch the Microsoft Virtual Academy (mva.microsoft.com) Powershell videos on getting started and then advanced tools & scripts – that will self enable you to a great extent. Probably the best way to train yourself.

    • #82103

      IT_Support
      Participant

      Thanks,
      Watching the first video already right now funily enough. thanks again, enjoy your weekend.

  • #82105

    IT_Support
    Participant

    Updated Script: just in case anyone else is after a similar script, I think its now working as I am getting results and no error so you can modify the below to your needs. thanks all:

    function Get-Monitor {
    Param
    [String[]]$Computernames = get-content "c:\scripts\machinelist.txt" }

    Foreach ($Computer in $Computernames){
    $ComputerSystemInfo = Get-WmiObject -Class win32_computersystem -ComputerName $Computer
    $MonitorInfo = Get-WmiObject -Namespace root\wmi -Class WmiMonitorID -ComputerName $Computer
    $BIOSInfo = Get-WmiObject -Class win32_bios -ComputerName $Computer

    $output = New-Object PSObject -Property @{
    'Name' = $ComputerSystemInfo.Name
    'Model' = $ComputerSystemInfo.Model
    'SerialNumber' = $BIOSInfo.SerialNumber
    'LoggedOnUser' = $ComputerSystemInfo.UserName
    }
    for ($i = 0; $i -lt $MonitorInfo.Length; $i++){
    $output | add-member -MemberType NoteProperty -Name "Monitor$i`Name" -Value $([system.text.encoding]::ascii.GetString($($MonitorInfo[0].ManufacturerName)))
    $output | Add-Member -MemberType NoteProperty -name "Monitor$i`Serial#" -Value $([system.text.encoding]::ascii.GetString($($MonitorInfo[0].SerialNumberid)))
    }
    $output
    }

    • #82685

      IT_Support
      Participant

      Hi All,
      I have come across a great script that seems to work,
      However just need to figure out where/how i can get it to include the PC's Serial Number:
      If anyone interested, here is the Script:
      And if anyone is able to spare me some time to help me figure out how to get the PC Serial Number that would be greatly appreciated.
      Thanks,
      —–

      
      Param(
      	[switch]$CSVReport,
      	[string]$CSVOutputFile = "C:\Test\AttachedMonitors.csv",
      	[switch]$HTMLReport = $true,
      	[string]$HTMLOutputFile = "C:\Test\AttachedMonitors.htm",
      	[switch]$EmailReportAsHTML,
      	[switch]$FromAD,
      	[switch]$FromFile,
      	[string]$FromFileLocation = "C:\Test\Servers.txt",
      	[switch]$Test
      )
      ### SMTP Mail Settings
      $SMTPProperties = @{
      	To = "ToUser@domain.com"
      	From = "FromUser@Domain.com"
      	Subject = "Monitor Inventory"
      	SMTPServer = "mail.domain.com"
      }
      
      $Results = @()
      $Count = 0
      
      if ($FromAD)
      {	### Attempts to Import ActiveDirectory Module. Produces error if fails.
      	Try { Import-Module ActiveDirectory -ErrorAction Stop }
      	Catch { Write-Host "Unable to load Active Directory module, is RSAT installed?"; Break }
      }
      
      ### HTML Header	
      $Header = @"
      
      	
      		TABLE {border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;margin-left: auto;margin-right: auto;}
      		TH {border-width: 1px;padding: 3px;border-style: solid;border-color: black;background-color: #808080;}
      		TD {border-width: 1px;padding: 3px;border-style: solid;border-color: black;}
      		.odd  { background-color:#ffffff; }
      		.even { background-color:#dddddd; }
      	
      
      
      	Attached Monitor Inventory Report
      
      "@
      
      
      Function ConvertTo-Char ($Array)
      {
      	$Output = ""
      	ForEach($char in $Array)
      	{	$Output += [char]$char -join ""
      	}
      	return $Output
      }
      
      Function Detect-VirtualMachine
      {
      	Param (
      		[string]$ComputerName
      	)
      	$VMModels = @("Virtual Machine","VMware Virtual Platform","Xen","VirtualBox")
      	$CheckPhysicalOrVMQuery = Get-WmiObject -ComputerName $ComputerName -Query "Select * FROM Win32_ComputerSystem" -Namespace "root\CIMV2" -ErrorAction Stop
      	if ($VMModels -contains $CheckPhysicalOrVMQuery.Model)
      	{	$IsVM = $True
      	}
      	Else
      	{	$IsVM = $False
      	}
      	Return $IsVM
      }
      
      Function Set-AlternatingRows
      {
      	< #
      	.SYNOPSIS
      		Simple function to alternate the row colors in an HTML table
      	.DESCRIPTION
      		This function accepts pipeline input from ConvertTo-HTML or any
      		string with HTML in it.  It will then search for  and replace 
      		it with .  With the combination of CSS it
      		can set alternating colors on table rows.
      		
      		CSS requirements:
      		.odd  { background-color:#ffffff; }
      		.even { background-color:#dddddd; }
      		
      		Classnames can be anything and are configurable when executing the
      		function.  Colors can, of course, be set to your preference.
      		
      		This function does not add CSS to your report, so you must provide
      		the style sheet, typically part of the ConvertTo-HTML cmdlet using
      		the -Head parameter.
      	.PARAMETER Line
      		String containing the HTML line, typically piped in through the
      		pipeline.
      	.PARAMETER CSSEvenClass
      		Define which CSS class is your "even" row and color.
      	.PARAMETER CSSOddClass
      		Define which CSS class is your "odd" row and color.
      	.EXAMPLE $Report | ConvertTo-HTML -Head $Header | Set-AlternateRows -CSSEvenClass even -CSSOddClass odd | Out-File HTMLReport.html
      	
      		$Header can be defined with a here-string as:
      		$Header = @"
      		
      		TABLE {border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}
      		TH {border-width: 1px;padding: 3px;border-style: solid;border-color: black;background-color: #6495ED;}
      		TD {border-width: 1px;padding: 3px;border-style: solid;border-color: black;}
      		.odd  { background-color:#ffffff; }
      		.even { background-color:#dddddd; }
      		
      		"@
      		
      		This will produce a table with alternating white and grey rows.  Custom CSS
      		is defined in the $Header string and included with the table thanks to the -Head
      		parameter in ConvertTo-HTML.
      	.NOTES
      		Author:         Martin Pugh
      		Twitter:        @thesurlyadm1n
      		Spiceworks:     Martin9700
      		Blog:           www.thesurlyadmin.com
      		
      		Changelog:
      			1.0         Initial function release
      	.LINK
      		http://community.spiceworks.com/scripts/show/1745-set-alternatingrows-function-modify-your-html-table-to-have-alternating-row-colors
      	#>
      	[CmdletBinding()]
      	Param(
      		[Parameter(Mandatory=$True,ValueFromPipeline=$True)]
      		[string]$Line,
      	   
      		[Parameter(Mandatory=$True)]
      		[string]$CSSEvenClass,
      	   
      		[Parameter(Mandatory=$True)]
      		[string]$CSSOddClass
      	)
      	Begin {
      		$ClassName = $CSSEvenClass
      	}
      	Process {
      		If ($Line.Contains(""))
      		{	$Line = $Line.Replace("","")
      			If ($ClassName -eq $CSSEvenClass)
      			{	$ClassName = $CSSOddClass
      			}
      			Else
      			{	$ClassName = $CSSEvenClass
      			}
      		}
      		Return $Line
      	}
      }# End Set-AlternatingRows Function
      
      if ($FromAD){ $Computers = Get-ADComputer -Filter * -Properties Name }
      if ($FromFile){ $Computers = Get-Content $FromFileLocation }
      
      ForEach ($Computer in $Computers)
      {
      	$progress = @{
      		Activity = "Querying Connected Monitors on $ComputerName"
      		Status = "$Count of $($Computers.Count) completed"
      		PercentComplete = $Count / $($Computers.Count) * 100
      		Id = 0
      	}
      	Write-Progress @progress
      	
      	$Count++
      	
      	if ($FromAD)
      	{	$ComputerName = $Computer.DNSHostName
      	}
      	ElseIf ($FromFile)
      	{	$ComputerName = $Computer
      	}
      	ElseIf ($Test)
      	{	Write-Host "Test Mode Enabled" -ForegroundColor Yellow
      		$ComputerName = $Env:ComputerName
      	}
      	Try
      	{
      		if (-not ($Test))
      		{	$IsPhysicalMachine = Detect-VirtualMachine -ComputerName $ComputerName
      		}
      		Else
      		{	$IsPhysicalMachine = Detect-VirtualMachine -ComputerName "localhost"
      		}
      	}
      	Catch
      	{
      		if (-not ($Test))
      		{	Write-Host "ComputerName: $($ComputerName), caught an error checking if the computer was physical or virtual: $($Error[0])" -ForegroundColor Red -BackgroundColor Black
      		}
      		Else
      		{	Write-Host "ComputerName: $($ComputerName), caught an error checking if the computer was physical or virtual: $($Error[0])" -ForegroundColor Red -BackgroundColor Black
      		}
      		$Results += New-Object PSObject -Property @{
      			ComputerName = $ComputerName
      			Active = "N/A"
      			Manufacturer = "N/A"
      			UserFriendlyName = "N/A"
      			SerialNumber = "N/A"
      			WeekOfManufacture = "N/A"
      			YearOfManufacture = "N/A"
      			Status = "2 - Warning"
      			Message = "There was a problem checking if the computer was physical or virtual: $($Error[0])"
      		}
      		Continue
      	}
      	If ($IsPhysicalMachine -eq $false)
      	{
      		Try
      		{
      			if (-not ($Test))
      			{	$Query = Get-WmiObject -ComputerName $ComputerName -Query "Select * FROM WMIMonitorID" -Namespace root\wmi -ErrorAction Stop
      			}
      			Else
      			{	$Query = Get-WmiObject -Query "Select * FROM WMIMonitorID" -Namespace root\wmi -ErrorAction Stop
      			}
      
      			ForEach ($Monitor in $Query)
      			{    
      				$Results += New-Object PSObject -Property @{
      					ComputerName = $ComputerName
      					Active = $Monitor.Active
      					Manufacturer = ConvertTo-Char($Monitor.ManufacturerName)
      					UserFriendlyName = ConvertTo-Char($Monitor.userfriendlyname)
      					SerialNumber = ConvertTo-Char($Monitor.serialnumberid)
      					WeekOfManufacture = $Monitor.WeekOfManufacture
      					YearOfManufacture = $Monitor.YearOfManufacture
      					Status = "0 - OK"
      					Message = "N/A"
      				}
      			}
      			Continue
      		}
      		Catch
      		{
      			$Results += New-Object PSObject -Property @{
      				ComputerName = $ComputerName
      				Active = "N/A"
      				Manufacturer = "N/A"
      				UserFriendlyName = "N/A"
      				SerialNumber = "N/A"
      				WeekOfManufacture = "N/A"
      				YearOfManufacture = "N/A"
      				Status = "1 - Error"
      				Message = "Error: $($Error[0])"
      			}
      		}
      	}
      	Else
      	{	Write-Host "ComputerName: $($ComputerName) was a virtual machine. Skipping monitor inventory." -ForegroundColor Yellow
      		$Results += New-Object PSObject -Property @{
      			ComputerName = $ComputerName
      			Active = $false
      			Manufacturer = "N/A"
      			UserFriendlyName = "N/A"
      			SerialNumber = "N/A"
      			WeekOfManufacture = "N/A"
      			YearOfManufacture = "N/A"
      			Status = "N/A - Informational"
      			Message = "Virtual Machine, skipped monitor inventory."
      		}
      	}
      }
      
      ### Debugging to make sure there are results.
      #Write-Host "Results Count: $($Results.count)"
      
      If ($Results.count -gt 0)
      {	$Results = $Results | Select ComputerName,Active,Manufacturer,UserFriendlyName,SerialNumber,WeekOfManufacture,YearOfManufacture,Status,Message
      	if ($CSVReport)
      	{	$Results | Sort Status,ComputerName | Export-CSV -Path $CSVOutputFile -NoTypeInformation
      	}
      	if ($HTMLReport)
      	{	$Results | Sort Status,ComputerName | ConvertTo-HTML -Head $Header | Out-File $HTMLOutputFile
      	}
      	if ($EmailReportAsHTML)
      	{	$Body = $Results | Sort Status,ComputerName | ConvertTo-HTML -Head $Header | Out-String
      		Send-MailMessage @SMTPProperties -Body $Body -BodyAsHTML
      	}
      }
      Else
      {	Write-Output "There were 0 results in the `$Results array."
      }
      
    • #82717

      Naw Awn
      Participant

      I can't seem to locate this bit on your script. Well, this is how you get the serial number of a computer. Maybe assign it to a variable and stick to your report, also change the localhost to a computer name variable.

      (gwmi Win32_Bios -ComputerName localhost).SerialNumber
      

You must be logged in to reply to this topic.