1

I'm new to PowerShell and I try to read some monitor/display infos from clients.

I put together this script:

param(
[string]$ComputerName
)

$objWMi = get-wmiobject -namespace root\WMI -ComputerName $ComputerName -class WmiMonitorID | select WeekOfManufacture, YearOfManufacture, UserFriendlyName, SerialNumberID, ManufacturerName

$Userfn = ForEach-Object {($objWMi.UserFriendlyName -ne 0 | foreach {[char]$_}) -join"";}
$SerialNum = ForEach-Object {($objWMi.SerialNumberID -ne 0 | foreach {[char]$_}) -join"";}
$ManuName = ForEach-Object {($objWMi.ManufacturerName -ne 0 | foreach {[char]$_}) -join"";}
$Weekom = $objWMi.WeekOfManufacture
$Yearom = $objWMi.YearOfManufacture


Write-Host "1: $Userfn  | $ManuName | $SerialNum | $Weekom | $Yearom" 


Exit 0

It is called with .\myscript.ps1 -ComputerName clientdnsname and returns something like this:

1: P22W-5 ECO | FUS | YE7XXXXX | 46 | 2008.

Works like a charm, exactly what I need. There is one exception: if some client has more than one monitor attached the script returns something like this:

1: HP E272qHP E272q | HWPHWP | CNKXXXXCCNKYYYY | 40 40 | 2015 2015

How can I modify the output to split the result up if there is more than one monitor and output

1: HP E272q | HWP| CNKXXXX | 40 | 2015 2: HP E272q | HWP| CNKXXXX | 40 | 2015

The variables contain the infos for all monitors and I have no idea how to avoid this or how to split this up in one value per variable. Any ideas much appreciated!

EDIT: I need the result returned in one row like above because I feed this to another program.

3 Answers 3

2

Check out this script: http://www.activexperts.com/admin/scripts/wmiscripts/powershell/0073/

It doesn't handle converting the text like you do, but that's easy to rectify with the code you already have.

This modification should be pretty close to what you need:

function byteArrayToString($byteArray)
{
    if ($byteArray.Count -gt 0){
        return ($byteArray -ne 0 | foreach {[char]$_}) -join""
    }
    return "N/A"
}

$strComputer = "."

$objWMi = get-wmiobject -namespace root\WMI -computername localhost -Query "Select * from WmiMonitorID"

foreach ($obj in $objWmi)
{
    $Userfn = byteArrayToString($obj.UserFriendlyName)
    $SerialNum = byteArrayToString($obj.SerialNumberID)
    $ManuName = byteArrayToString($obj.ManufacturerName)
    $Weekom = $obj.WeekOfManufacture
    $Yearom = $obj.YearOfManufacture
    Write-Host "1: $Userfn  | $ManuName | $SerialNum | $Weekom | $Yearom" 
}
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks. I've seen this script before. Unfortunately I need the result returned in one row because I process the result in another program...Edited my post to clear things up. I also put a foreach loop around write-host in my script. This also outputs the row with doubled entries but just does it two times....
I updated the code to output on a single line for you. The "foreach" loop around your variable assignments is what was causing the problem for you.
Yay. I tried with a foreach loop around the variables too but did not removed ForEach-Object at the same time. Thanks!
I added a little function to do the string conversion. This way if you come to an empty value, it won't throw an error. DarkLite1's solution is more elegant though. So ideally, I would combine that function with his response.
2

I feel the need to add an extra answer. Please keep in mind that Write-Host is NOT the way to go. As Don Jones explains it kills puppies and there are plenty of better ways to achieve what you want.

First of all, by generating a PSCustomObject you can do a lot more.

Some examples:

Function Get-MonitorInfo {
    Param (
        [String]$ComputerName = $env:COMPUTERNAME
    )

    # For ease of reading the code we create a hashtable which we use wit 'Get-WmiObject', this is called 'Splatting'
    $WmiParams = @{
        Namespace    = 'root\WMI'
        ComputerName = $ComputerName
        Class        = 'WmiMonitorID'
    }

    # First we collect all the results in one variabla
    $Objects = Get-WmiObject @WmiParams | Select-Object WeekOfManufacture, YearOfManufacture, 
        UserFriendlyName, SerialNumberID, ManufacturerName

    # Then for each object in the variable '$Objects' we generate one line of output (an object)
    foreach ($Object in $Objects) {

        # The generated object will contain the following
        [PSCustomObject]@{
            FriendlyName      = ($Object.UserFriendlyName | ForEach-Object {[Char]$_}) -join ''
            SN                = ($Object.SerialNumberID | ForEach-Object {[Char]$_}) -join ''
            ManufacturerName  = ($Object.ManufacturerName | ForEach-Object {[char]$_}) -join ''
            ManufacturingWeek = $Object.WeekOfManufacture
            ManufacturingYear = $Object.YearOfManufacture
        }
    }
}

$Result = Get-MonitorInfo

# List all monitors:
$Result

# Only list Monitors with a FriendlyName starting with HP:
$Result | where {$_.FriendlyName -like 'HP*'}

# Only list Monitors with a FriendlyName starting with HP and show me the SN:
$Result | where {$_.FriendlyName -like 'HP*'} | Select-Object SN

# Count how many monitors we have on one machine:
$Result.Count

# Export everything to a file
$Result | Out-File -FilePath "$env:TEMP\Monitors.txt"
Start-Process "$env:TEMP\Monitors.txt"

As you can see, all these things would be difficult when only using Write-Host. Hopefully the examples above made it a bit more clear why you should not be using Write-Host in this case.

4 Comments

Thank you! I did not know about this. I'm proccesing this script with another program which is executing the script and expects a string as a result printed to standard output (in one row).
You're welcome, hope you learned something. Output to a string is also possible: $Result | Select @{N='String';E={"$($_.FriendlyName) | $($_.SN) | $($_.ManufacturerName) | $($_.ManufacturingWeek) | $($_.ManufacturingYear)"}} | Out-String or if you mean viewing the content on one line you can also do $Result | Format-Table.
Thanks a bunch! The hashtable does not seem to work, it always returns the infos from localhost...Also is there a way to just return this one line? Your first example outputs String ------ P22W-5 ECO | YE7XXXXX | FUS | 46 | 2008 How can I avoid the whole "String"-line?
With an object everything is possible, please try this: Get-MonitorInfo -ComputerName MyPCNameHere | Select @{N='String';E={"$($_.FriendlyName) | $($_.SN) | $($_.ManufacturerName) | $($_.ManufacturingWeek) | $($_.ManufacturingYear)"}} | Select -ExpandProperty String
1

I tried to propose the below as a modification to DarkLite1's answer, but apparently somebody thought it was "deliberately destructive" and rejected it . . .

In answer to your question, duenni, the below modification to DarkLite1's code will give you the ability to output the data in the format you're looking for.

Function byteArrayToString($byteArray)
{
    if ($byteArray.Count -gt 0){
        return ($byteArray -ne 0 | foreach {[char]$_}) -join""
    }
    return "N/A"
}

Function Get-MonitorInfo {
    Param (
        [String]$ComputerName = $env:COMPUTERNAME
    )

    # For ease of reading the code we create a hashtable which we use wit 'Get-WmiObject', this is called 'Splatting'
    $WmiParams = @{
        Namespace    = 'root\WMI'
        ComputerName = $ComputerName
        Class        = 'WmiMonitorID'
    }

    # First we collect all the results in one variabla
    $Objects = Get-WmiObject @WmiParams | Select-Object WeekOfManufacture, YearOfManufacture, 
        UserFriendlyName, SerialNumberID, ManufacturerName

    # Then for each object in the variable '$Objects' we generate one line of output (an object)
    foreach ($Object in $Objects) {

        # The generated object will contain the following
        [PSCustomObject]@{
            FriendlyName      = byteArrayToString($Object.UserFriendlyName)
            SN                = byteArrayToString($Object.SerialNumberID)
            ManufacturerName  = byteArrayToString($Object.ManufacturerName)
            ManufacturingWeek = $Object.WeekOfManufacture
            ManufacturingYear = $Object.YearOfManufacture
        } | Add-Member -MemberType ScriptMethod -Name ToString -Force -Value {
            "1: $($this.FriendlyName) | $($this.ManufacturerName) | $($this.SN) | $($this.ManufacturingWeek) | $($this.ManufacturingYear)"
        } -PassThru
    }
}

$Result = Get-MonitorInfo

# List all monitors:
$Result

# List all monitors as formatted strings
foreach ($monitor in $Result) {$monitor.ToString()}

# Only list Monitors with a FriendlyName starting with HP:
$Result | where {$_.FriendlyName -like 'HP*'}

# Only list Monitors with a FriendlyName starting with HP and show me the SN:
$Result | where {$_.FriendlyName -like 'HP*'} | Select-Object SN

# Count how many monitors we have on one machine:
$Result.Count

# Export everything to a file
$Result | Out-File -FilePath "$env:TEMP\Monitors.txt"
Start-Process "$env:TEMP\Monitors.txt"

The new function can be called as follows:

foreach ($monitor in $Result) {$monitor.ToString()}

3 Comments

Thanks! Does it work for you? If i call it with .\myscript.ps1 -ComputerName hostxy it alway returns the infos from localhost. I tried to modify $Result = Get-MonitorInfo to $Result = Get-MonitorInfo -ComputerName $ComputerName but this won't work.
Well, I think I got this. Have to use another Param-block at the beginning of the ps1-file, like: param( [string]$HostName ). This param is then passed to the function with $Result = Get-MonitorInfo($HostName). Then I can call the script like this myscript.ps1 -HostName hostxy
You can do that, or you could just dot-source the ps1 file in, then call Get-MonitorInfo -ComputerName whatever For details, check out this page and search for "dot source": technet.microsoft.com/en-us/library/hh847841.aspx

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.