Variable is array instead of string? - powershell

I wrote this small script and when I test Write-Host $serial it appears fine, but when it is running in the background $serial seems to contain an array.
It tries to rename computer to C000#{SerialNumber=F7ZL3F2} instead of just C000F7ZL3F2.
What should I do to just get string not this array?
Import-Module ActiveDirectory
Get-ADComputer -Filter {Name -like 'DESKTOP-*'} -Properties * | Select Name, DNSHostName | ForEach-Object {
$rtn = Test-Connection -CN $_.dnshostname -Count 1 -BufferSize 16 -Quiet
if ($rtn -match 'True') {
$serial = Get-WMIObject Win32_Bios -ComputerName $_.name | Select-String SerialNumber
$serial = "C000$serial"
// Write-Host $serial
Rename-Computer -ComputerName $_.name -NewName $serial -DomainCredential $mycreds -Force -Restart
}
}

There are two mistakes to be pointed out in your code -
$serial = Get-WMIObject Win32_Bios -ComputerName $_.name | Select-String SerialNumber
The Select-String cmdlet searches for text and text patterns in input strings and files. Where as the basetype output of Get-WMIObject Win32_Bios is System.Management.ManagementBaseObject
(Get-WMIObject Win32_Bios).Gettype()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True ManagementObject System.Management.ManagementBaseObject
In such cases, instead of Select-String, you can use Select-Object to choose amongst the properties. Since, Serial Number is one of the properties returned by your input command.
$serial = "C000$serial"
The output of $serial will be something like this:
SerialNumber
5CXXXXYYYXZZZ
Again, you can call it directly by $serial.SerialNumber. So your overall code will be
Import-Module ActiveDirectory
Get-ADComputer -Filter {Name -like 'DESKTOP-*'} -Properties * | Select Name, DNSHostName | ForEach-Object {
$rtn = Test-Connection -CN $_.dnshostname -Count 1 -BufferSize 16 -Quiet
if ($rtn -match 'True') {
$serial = Get-WMIObject Win32_Bios -ComputerName $_.name |
Select-Object SerialNumber
$serial = "C000$($serial.SerialNumber)"
Rename-Computer -ComputerName $_.name -NewName $serial -DomainCredential $mycreds -Force -Restart
}
}
Or you can use -ExpandProperty parameter of the Select-Object cmdlet like
$serial = Get-WMIObject Win32_Bios -ComputerName $_.name |
Select-Object -ExpandProperty SerialNumber
$serial = "C000$serial"

Try changing this line:
$serial = Get-WMIObject Win32_Bios -ComputerName $_.name |
Select-String SerialNumber
to this:
$serial = (Get-WMIObject Win32_Bios -ComputerName $_.name).SerialNumber
or this:
$serial = Get-WMIObject Win32_Bios -ComputerName $_.name |
Select-Object -ExpandProperty SerialNumber

Why are you using Select-String? I would use Select-Object and then -ExpandProperty
Import-Module ActiveDirectory
Get-ADComputer -Filter {Name -like 'DESKTOP-*'} -Properties * | Select Name, DNSHostName | ForEach-Object {
$rtn = Test-Connection -CN $_.dnshostname -Count 1 -BufferSize 16 -Quiet
if ($rtn -match 'True') {
$serial = Get-WMIObject Win32_Bios -ComputerName $_.name | Select-Object -ExpandProperty SerialNumber
$serial = "C000$serial"
// Write-Host $serial
Rename-Computer -ComputerName $_.name -NewName $serial -DomainCredential $mycreds -Force -Restart
}
}

Related

Format output in Powershell

I have a small code in my script that is working well. I'm just annoyed with the output..
My output looks like this:
11.11.111.123
Model
-----
HP ZBook Studio G5
csname : XXXXXXX
LastBootUpTime : 22/Apr/2022 08:10:57
But I want it like this:
IP Address: 11.11.111.123
Model: HP ZBook Studio G5
csname: xxxxx
LastBootUpTime: 22/Apr/2022 08:10:57
This is the script:
Get-WmiObject Win32_NetworkAdapterConfiguration -Computername $pcName |
Where { $_.IPAddress } |
Select -Expand IPAddress |
Where { $_ -like '10.11*' -or $_ -like '10.12*'}
Get-WmiObject -Class Win32_ComputerSystem -Computername $pcName | Select Model
Get-WmiObject win32_operatingsystem -Computername $pcName -ea stop | select csname, #{LABEL='LastBootUpTime';EXPRESSION={$_.ConverttoDateTime($_.lastbootuptime)}} | format-list
Since the output is produced by 3 different classes the way around it is create a new object to merge them:
$IPs = Get-CimInstance Win32_NetworkAdapterConfiguration -ComputerName $pcName |
Where-Object { $_.IPAddress -like '10.11*' -or $_.IPAddress -like '10.12*' }
$Model = (Get-CimInstance -Class Win32_ComputerSystem -ComputerName $pcName).Model
$OS = Get-CimInstance win32_operatingsystem -EA Stop -ComputerName $pcName
[pscustomobject]#{
'IP Address' = $IPs.IpAddress -join ', '
Model = $Model
csname = $OS.CSName
LastBootUpTime = $OS.LastBootUpTime.ToString()
}

Get computer OS version

This script is working fine to get the OS version. I need to know who to get only Microsoft Windows 10 Pro in the result
$Computers = Get-Content C:\computerlist
Foreach($Computer in $Computers)
{
Get-WmiObject Win32_OperatingSystem -ComputerName $Computer -ErrorAction SilentlyContinue | Select-Object CSName, Caption | sort CSName
}
I'm not sure if I understandy you correctly, but I think you need Where-Object:
$Computers = Get-Content C:\computerlist
Foreach($Computer in $Computers)
{
Get-WmiObject Win32_OperatingSystem -ComputerName $Computer -ErrorAction SilentlyContinue | Select-Object CSName, Caption | where Caption -eq "Microsoft Windows 10 Pro" | sort CSName
}
If you want just the Caption value, use Select-Object -ExpandProperty Caption:
foreach($Computer in $Computers)
{
Get-WmiObject Win32_OperatingSystem -ComputerName $Computer -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Caption
}

Powershell: Pipe variable $_ in if statement?

I have the following short script to grab serial numbers of computers and monitors in an OU, which works fine:
Import-Module ActiveDirectory
$searchbase = "OU=some,OU=organisational,OU=units,DC=somedomain,DC=local"
Write-Host ""
Write-Host "Serial Numbers for Computers and Monitors in" $searchbase
Write-Host "--"
Get-ADComputer -SearchBase $searchbase -Filter '*' | `
Select-Object -Expand Name | %{Write-Host ""; echo $_ ; Get-WMIObject -Class Win32_BIOS -ComputerName $_ | Select-Object -Expand SerialNumber; `
$monitor = gwmi WmiMonitorID -Namespace root\wmi -computername $_; ($monitor.SerialNumberID | foreach {[char]$_}) -join ""};
This script doesn't check to see if the computer is online before attempting to fetch the WMIObject, so if a computer is offline it takes ages before the RPC call times out.
I tried to modify the script to use the Test-Connection cmdlet before trying to get the WMIObject:
Import-Module ActiveDirectory
$searchbase = "OU=some,OU=organisational,OU=units,DC=somedomain,DC=local"
Write-Host ""
Write-Host "Serial Numbers for Computers and Monitors in" $searchbase
Write-Host "--"
Get-ADComputer -SearchBase $searchbase -Filter '*' | `
Select-Object -Expand Name | `
if (Test-Connection -ComputerName $_ -Quiet) {
%{Write-Host ""; echo $_ ; Get-WMIObject -Class Win32_BIOS -ComputerName $_ | Select-Object -Expand SerialNumber; `
$monitor = gwmi WmiMonitorID -Namespace root\wmi -computername $_; ($monitor.SerialNumberID | foreach {[char]$_}) -join ""};}
}
else {
Write-Host ""; Write-Host $_ "is offline";
}
I'm sure I'm doing something syntactically stupid. Can someone point me in the right direction?
You can't pipe directly to an if statement, only to cmdlets.
Put the if statement inside the ForEach-Object block (% is an alias for ForEach-Object):
... | Select-Object -Expand Name | `
%{
if (Test-Connection -ComputerName $_ -Quiet) {
# Get-WmiObject in here
}
else {
Write-Host ""; Write-Host $_ "is offline";
}
}
If you don't care about writing each machine's status to the host, you could also filter out offline computers with Where-Object(alias ?):
... | Select-Object -Expand Name | ?{
Test-Connection $_ -Quiet
} | % {
Get-WmiObject -ComputerName $_
}
In addition to the answer from #Mathias R. Jessen, you can get rid of the backticks for line continuation.
They are not needed if the end of the line infers there is another block of code required for the statement. Like | or { or (.
"foo", "bar" |
% {$_}
works just fine...

Remove white spaces between commands output in powershell

I've got an script and I want to remove the white spaces that powershell puts by default in the output result. Is there any way of doing it?
=======Computer1=======
Microsoft Windows 8.1 Pro
Name : Computer1
Model : Vostro 200
Manufacturer : Dell Inc.
SerialNumber : 012345
This is what I want:
=======Computer1=======
Microsoft Windows 8.1 Pro
Name : Computer1
Model : Vostro 200
Manufacturer : Dell Inc.
SerialNumber : 012345
This is my script:
$Computers=Import-Csv C:\Powershell\test.csv
$ResultsPath="C:\Powershell\test.txt"
foreach ($i in $Computers.Name) {
"="*7 + $i + "="*7
if (Test-Connection $i -quiet) {
(Get-WmiObject -class Win32_OperatingSystem -ComputerName $i).Caption
Get-WmiObject -class Win32_Computersystem -ComputerName $i | Select-Object Name, Model, Manufacturer | Format-List
Get-WmiObject win32_SystemEnclosure -ComputerName $i | Select-Object SerialNumber | Format-List }
else { "nothing" }
}
While Trim will do what you need, this is not a PowerShell way. Here is revised script, that works with objects internally and writes output the way you want.
$Computers = Import-Csv 'C:\Powershell\test.csv'
$ResultsPath = 'C:\Powershell\test.txt'
foreach ($i in $Computers.Name) {
$Header = '='*7 + $i + '='*7
Write-Output $Header
if (Test-Connection $i -quiet)
{
$Os = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $i | Select-Object -ExpandProperty Caption
$Info = Get-WmiObject -Class Win32_Computersystem -ComputerName $i | Select-Object Name, Model, Manufacturer
$Sn = Get-WmiObject -Class Win32_SystemEnclosure -ComputerName $i | Select-Object -ExpandProperty SerialNumber
$PC = New-Object -TypeName psobject -Property #{
OperatingSystem = $Os
Name = $Info.Name
Model = $Info.Model
Manufacturer = $Info.Manufacturer
SerialNumber = $Sn
} | Select-Object OperatingSystem, Name, Model, Manufacturer, SerialNumber
Write-Output ($PC | Format-List | Out-String).Trim()
}
else
{
Write-Output 'nothing'
}
}
Convert output to string and trim it:
"="*7 + $i + "="*7
if (Test-Connection $i -quiet) {
(Get-WmiObject -class Win32_OperatingSystem -ComputerName $i).Caption
(Get-WmiObject -class Win32_Computersystem -ComputerName $i | Select-Object Name, Model, Manufacturer | Format-List | Out-String).Trim()
(Get-WmiObject win32_SystemEnclosure -ComputerName $i | Select-Object SerialNumber | Format-List | Out-String).Trim() }
else { "nothing" }

How to store data from foreach function in HTML file in powershell and get Physicall ram

I have written a for each file which stores the BIOS information of the systems in a network and the result is being displayed on my console but I want them to be in a HTML file in an order.
Code:
$arrComputers = get-Content -Path "C:\Computers.txt"
foreach ($strComputer in $arrComputers)
{
$colItems = get-wmiobject -class "Win32_BIOS" -namespace "root\CIMV2" `
-computername $strComputer
foreach ($objItem in $colItems)
{
write-host "Computer Name: " $strComputer
write-host "BIOS Version: " $objItem.BIOSVersion
}
$colItems1 = get-wmiobject -class Win32_logicaldisk -Filter "DeviceID = 'C:'" -computername $strComputer
foreach ($objItem1 in $colItems1)
{
$e=$objItem1.freeSpace/1GB
write-host "Total Space: " $e
}
$colItems4 = Get-WMIObject -class Win32_PhysicalMemory -computername $strComputer
$colItems5=$colItems4 | Measure-Object -Property capacity -Sum
foreach ($objItem4 in $colItems5)
{
$e4=$colItems5.Sum/1GB
write-host "Memory : " $e4
}
}
Can you please help me in saving all the above data in HTML
You need to look at the ConvertTo-Html cmdlet.
Get-WmiObject -Class Win32_BIOS -ComputerName localhost,$env:COMPUTERNAME |
Select PSComputerName,Version,SerialNumber |
ConvertTo-Html |
Out-File c:\test3.html
Another method based on OPs update:
$arrComputers = get-Content -Path "C:\Computers.txt"
$arrComputers | ForEach-Object { Get-WMIObject -Class Win32_BIOS -ComputerName $_ } |
Select PSComputerName, Version, Manufacturer |
ConvertTo-Html |
Out-File C:\test4.html