Sort and format in email - powershell

I'm new to Powershell and I'm trying to send the output by email of the following piece of code, if I send it to the console, it is formatted nicely, but when I pipeline it into an email, the retrieved objects are not lined up.
$bios = Get-WmiObject Win32_BIOS -ComputerName localhost
$os = Get-WmiObject `Win32_OperatingSystem -ComputerName localhost
$Proc = Get-WmiObject Win32_processor -ComputerName localhost | Select-Object -First 1
$memory = Get-WmiObject Win32_physicalmemory -ComputerName localhost
$system = Get-WmiObject Win32_ComputerSystem -ComputerName localhost
$Systeminfo = New-Object PSObject -Property #{
'ComputerName' = $proc.SystemName;
'Manufacturer' = $bios.Manufacturer;
'Model' = $system.Model;
'BIOS Version' = $bios.Version;
'Serial Number' = $bios.SerialNumber;
'Number of Processors ' = $system.NumberOfProcessors;
'Processor Name' = $proc.name;
'Logical Processor' = $system.NumberOfLogicalProcessors;
'Speed (MHZ)' = $proc.CurrentClockSpeed;
'RAM (GB)' = $system.TotalPhysicalMemory / 1GB -as [int];
'Used RAM slots' = $memory.count;
'OSVersion' = $os.Caption
}
$Systeminfo = $Systeminfo | Out-String
Also, is there a way to rearrange the order they appear, for example, I would like the computername to be first in the array, but it appears in the middle?

If you have PowerShell 3.0 you could create the object using [ordered]
$Systeminfo = [pscustomobject][ordered] #{
'ComputerName' = $proc.SystemName;
'Manufacturer' = $bios.Manufacturer;
'Model' = $system.Model;
'BIOS Version' = $bios.Version;
'Serial Number' = $bios.SerialNumber;
'Number of Processors ' = $system.NumberOfProcessors;
'Processor Name' = $proc.name;
'Logical Processor' = $system.NumberOfLogicalProcessors;
'Speed (MHZ)' = $proc.CurrentClockSpeed;
'RAM (GB)' = $system.TotalPhysicalMemory / 1GB -as [int];
'Used RAM slots' = $memory.count;
'OSVersion' = $os.Caption
}
That should output the properties in the order they were defined. Else you would need to use a select statement to order the properties that you want.
$Systeminfo | Select-Object ComputerName,Manufacturer,Model,"BIOS Version","Serial Number","Number of Processors","Processor Name","Logical Processor","Speed (MHZ)","RAM (GB)","Used RAM slots",OSVersion

Related

I want to get details of task manger users tab about ram and cpu utilization

I have following script, i want to get each users details of ram and cpu utilization separately in csv file. but from this script i am getting all users details in a single line instead of individually user based resources utilization details in csv file.
This is my Powershell code
GC c:\List.txt | % {
$xl = New-Object -ComObject "Excel.Application"
$xl.Visible = $true
$xl.DisplayAlerts = $false #for debugging, no prompts to save, etc.
$ConvertToGB = (1024 * 1024 * 1024)
$wkbk = $xl.Workbooks.Add()
$sheet = $wkbk.WorkSheets.Item(1)
$sheet.Name = "Transposed"
$Comp = $_
If (Test-Connection $Comp -Quiet) {
$Luser = (Get-WmiObject -class win32_process -Filter "Name='Explorer.exe'" -ComputerName $Comp |
% {$_.GetOwner().User} | Sort-Object -Unique) -join ","
$Mem = GWMI -Class win32_operatingsystem -computername $COMP
New-Object PSObject -Property #{
Server = $Comp
"CPU_Usage" = "$((GWMI -ComputerName $COMP win32_processor | Measure-Object -property LoadPercentage -Average).Average)"
"Memory_Usage" = "$("{0:N2}" -f ((($Mem.TotalVisibleMemorySize - $Mem.FreePhysicalMemory)*100)/ $Mem.TotalVisibleMemorySize)) %"
"DiskSpace" = "$("{0:N2}" -f (Get-WmiObject -Class win32_logicaldisk -ComputerName $COMP -Filter "DriveType = 3"| Select-Object "Size","FreeSpace"))"
#$Comp = ($disk.Size / $ConvertToGB),($disk.FreeSpace / $ConvertToGB)
"logged_Users" = $Luser
}
}
Else {
}
$results = Get-Service -Name *bits*| Select Server #,"CPU usage","Memory usage","DiskFreeSpace","logged Users"
$column = 1
$row = 1
foreach ($psRow in $results) {
foreach ($item in $psRow.PSObject.Properties) {
$sheet.Cells.Item($row, $column) = $item.Name
$column++
#$sheet.Cells.Item($row, $column) = $item."CPU","Memory_Usage","DiskSpace","logged_Users"
$row++
$column--
}
} }
$obj =New-Object PSObject -Property #{
Server = $Comp
"CPU_Usage" = "$((GWMI -ComputerName $COMP win32_processor | Measure-Object -property LoadPercentage -Average).Average)"
"Memory_Usage" = "$("{0:N2}" -f ((($Mem.TotalVisibleMemorySize - $Mem.FreePhysicalMemory)*100)/ $Mem.TotalVisibleMemorySize)) %"
"DiskSpace" = Get-WmiObject -Class win32_logicaldisk -ComputerName $COMP -Filter "DriveType = 3"| Select-Object "Size","FreeSpace"
#$Comp = ($disk.Size / $ConvertToGB),($disk.FreeSpace / $ConvertToGB)
"logged_Users" = $Luser
}
Write-Output "DiskSpace, $($obj.DiskSpace.Size), $($obj.DiskSpace.FreeSpace)"
Write-Output "Server, $($obj.Server)"
Write-Output "Memory_Usage, $($obj.Memory_Usage)"
Write-Output "logged_Users, $($obj.logged_Users)"
Write-Output "CPU_Usage, $($obj.CPU_Usage)"
$obj | ConvertTo-Csv
These are the results i am getting
Memory_Usage : 91.90 %
CPU_Usage : 99
Server : 127.0.0.1
logged_Users : user1,user2,user3,userA
DiskSpace : {#{Size=718642417664; FreeSpace=317923561472}, #{Size=214747312128; FreeSpace=182724562944}, #{Size=26507997184; FreeSpace=3710320640},
#{Size=1099511627776; FreeSpace=989560467456}}
I need this type of result in csv
logged users | Memory Usage in MB | CPU Usage % |
User1 25300 8
User2 33658 15
User3 48793 7
UserA 23564 5
why don't you use select-object? I can't test it b/c your script doesn't have the full code for me to test it, but it would be a little something like:
get-psdrive | Where Free* | Select-Object Name, #{Name='UsedGB'; Expression={$_.Used/1GB}}, #{Name='FreePerc'; Expression={'{0:p0}' -f((($_.Used)/1GB) / (($_.Free + $_.Used)/1GB))}}, #{Name='TotalSize'; Expression={($_.Free + $_.Used)/1GB}}
Result:
Name UsedGB FreePerc TotalSize
---- ------ -------- ---------
A 192.771030426025 81% 238.473628997803
C 336.458614349365 36% 930.742183685303
D 7043.1279296875 95% 7452.00390625
E 110.902645111084 47% 238.473628997803
You can use this to build the table you want.
From there, to export it to csv; I would assume you can export it with a pipe follow by export-csv -path (Destination + file name) -NoTypeInformation

Combining results from variables into hash table and display all values

My codes below gather boot time, server specs, disks, etc and stored into multiple variables. Then, i throw them into a new object to display the results nicely. The problem with displaying disks results, i don't mind that it displays all disks in one column but it doesn't show all of the disks. Using Format-table -autosize doesn't solve the problem.
If i can't fit all values in one column, what is the right approach to display drives letter in its own assigned field, dynamically.
IE; Column1 for value of disk1, Column 2 for value of disk 2...
I've removed some codes below to reduce the amount of lines.
$BootTime = GET-WmiObject win32_Operatingsystem -ComputerName $server -EA
STOP | select #{n='ServerName';e={$_.csname}},#{n='LastBootUpTime';e={$_.ConverttoDateTime($_.lastbootuptime)}} ,#{n='LocalTime';e={$_.ConverttoDateTime($_.LocalDateTime)}}
$Disks = Get-WmiObject win32_logicaldisk -ComputerName $server -Filter Drivetype=3 |`
Select-Object #{n = "Drive Letter";e = {$_.DeviceID}},`
#{n = "Total(GB)";e = {"{0:N1}" -f( $_.Size / 1gb)}},`
#{n = "FreeSpace(GB)";e = {"{0:N1}" -f( $_.Freespace / 1gb ) }},`
#{n = "FreeSpace(%)"; e = {"{0:P0}" -f ($_.freespace/$_.size)}}
New-Object -Type PSObject -Property #{
ServerName = $BootTime.Servername
LastBootTime = $BootTime.LastBootUptime
LocalTime = $BootTime.LocalTime
UpTime = $BootTime.UpTime
OS = $BootTime.OS
Domain = $Domain.Domain
Drive = $Disks."Drive Letter"
"Disks(GB)" = $Disks."Total(GB)"
"FreeSpace(GB)" = $Disks."FreeSpace(GB)"
"FreeSpace(%)" = $Disks."FreeSpace(%)"
}
}
CATCH
{
New-Object -Type PSObject -Property #{
ServerName = $Server
LastBootTime = "Try Pinging"
LocalTime = "WMI Not Responding"
UpTime = "Possibly WMI not functioning or server is hung"#$null
OS = $null
Drive = $null
"Disks(GB)" = $null
"FreeSpace(GB)" = $null
"FreeSpace(%)" = $null
"Memory(GB)" =$null
PhysicalCPU = $null
CPUName = $null
Cores = $null
Manufacturer = $null
Model = $null
}
}
}
$Output| Select ServerName,LastBootTime, LocalTime, UpTime,Domain,OS, PhysicalCPU, CPUName, Cores, "Memory(GB)", Drive, "Disks(GB)", "FreeSpace(GB)", "FreeSpace(%)" , Manufacturer, Model
Current Results:
Drive : {C:, E:, F:, G:...}
Disks(GB) : {149.7, 500.0, 1,945.0, 1,024.0...}
FreeSpace(GB) : {90.0, 358.6, 1,411.1, 909.9...}
FreeSpace(%) : {60%, 72%, 73%, 89%...}
Desired Results:
Drive : {C:, E:, F:, G:,H:}
Disks(GB) : {149.7, 500.0, 1,945.0, 1,024.0,100}
OR
Drive1 : C:
Drive2: D:
Disk(GB) 1 :149.7
Disk(GB) 2 : 500.0
This will be my answer:
$server="localhost"
$BootTime = GET-WmiObject win32_Operatingsystem -ComputerName $server -EA STOP | select #{n='ServerName';e={$_.csname}},#{n='LastBootUpTime';e={$_.ConverttoDateTime($_.lastbootuptime)}},#{n='LocalTime';e={$_.ConverttoDateTime($_.LocalDateTime)}},Caption,OSArchitecture
$Disks = Get-WmiObject win32_logicaldisk -ComputerName $server -Filter Drivetype=3 | Select-Object #{n = "Drive Letter";e = {$_.DeviceID}},#{n = "Total(GB)";e = {"{0:N1}" -f( $_.Size / 1gb)}},#{n = "FreeSpace(GB)";e = {"{0:N1}" -f( $_.Freespace / 1gb ) }},#{n = "FreeSpace(%)"; e = {"{0:P0}" -f ($_.freespace/$_.size)}}
try{
foreach($disk in $disks){
New-Object -Type PSObject -Property #{
ServerName = $BootTime.Servername
LastBootTime = $BootTime.LastBootUptime
LocalTime = $BootTime.LocalTime
#UpTime = $BootTime.UpTime #not in code
OS = $BootTime.Caption
OSArchitecture = $BootTime.OSArchitecture
Domain = $Domain.Domain
"Letter"= $disk."Drive Letter"
"Disk(GB)" = $disk."Total(GB)"
"FreeSpace(GB)" = $disk."FreeSpace(GB)"
"FreeSpace(%)" = $disk."FreeSpace(%)"
}
}
}
CATCH{
Write-Error $_.Exception.Message
exit -1
}

powershell drives calculator

So I have the below code which works quite well but for some reason it's only calculating my D: drive and not also my C: drive?
$computerName = Get-Wmiobject Win32_ComputerSystem
$computerOS = Get-Wmiobject Win32_OperatingSystem
$computerHDD = Get-Wmiobject Win32_LogicalDisk -Filter drivetype=3
ForEach($HDD in $computerHDD){
$txtObject = New-Object PSObject -property #{
'ComputerName' = $computerName.Name
'ComputerModel' = $computerName.Model
'SerialNumber' = $computerName.SerialNumber
'HDDSize' = "{0:N2}" -f ($HDD.Size/1GB)
'HDDFree' = "{0:P2}" -f ($HDD.FreeSpace/$HDD.Size)
'OS' = $computerOS.caption
'OS_type' = $computerOS.OSArchitecture
'User' = $computerName.UserName
}
}
$txtObject | Select-Object ComputerName, ComputerModel, SerialNumber, HDDSize, HDDFree, OS, Os_type, User | Out-File "$PSSCriptRoot\computer_info.txt" -Append
seems like you would need to make an array. Try this...
$computerName = Get-Wmiobject Win32_ComputerSystem
$computerOS = Get-Wmiobject Win32_OperatingSystem
$computerHDD = Get-Wmiobject Win32_LogicalDisk -Filter drivetype=3
$output = #()
ForEach($HDD in $computerHDD){
$txtObject = New-Object PSObject -property #{
'ComputerName' = $computerName.Name
'ComputerModel' = $computerName.Model
'SerialNumber' = $computerName.SerialNumber
'HDDSize' = "{0:N2}" -f ($HDD.Size/1GB)
'HDDFree' = "{0:P2}" -f ($HDD.FreeSpace/$HDD.Size)
'OS' = $computerOS.caption
'OS_type' = $computerOS.OSArchitecture
'User' = $computerName.UserName
}
$output += $txtObject
}
$output | Select-Object ComputerName, ComputerModel, SerialNumber, HDDSize, HDDFree, OS, Os_type, User | Out-File "$PSSCriptRoot\computer_info.txt" -Append
You're overwriting $txtObject on every iteration of the loop, so your output only contains the drive from the final iteration. Instead, you should be initializing $txtObject as an array and then appending each drive's information to that:
$computerHDD = Get-Wmiobject Win32_LogicalDisk -Filter drivetype=3
$txtObject = #()
ForEach($HDD in $computerHDD){
$txtObject += New-Object PSObject -property #{
# ...
}
}
$txtObject | Select-Object ... | Out-File "$PSSCriptRoot\computer_info.txt" -Append
Better yet, you can eliminate the loop and the variable and just use the pipeline:
$computerName = Get-WmiObject Win32_ComputerSystem
$computerOS = Get-WmiObject Win32_OperatingSystem
Get-WmiObject Win32_LogicalDisk -Filter drivetype=3 `
| ForEach-Object -Process {
New-Object PSObject -Property #{
'ComputerName' = $computerName.Name
'ComputerModel' = $computerName.Model
'SerialNumber' = $computerName.SerialNumber
'HDDSize' = "{0:N2}" -f ($_.Size/1GB)
'HDDFree' = "{0:P2}" -f ($_.FreeSpace/$_.Size)
'OS' = $computerOS.caption
'OS_type' = $computerOS.OSArchitecture
'User' = $computerName.UserName
};
} | Out-File "$PSSCriptRoot\computer_info.txt" -Append
Note that New-Object above is nearly identical to your original code except $_ has to be used instead of $HDD.

Adding new item into XML output file

I would like to combined the external IP address with the current hardware information output file.
PC info
#lists computer information
$cpu = Get-WmiObject -Class Win32_Processor
$mb = Get-WmiObject -Class Win32_BaseBoard
$bios = Get-WmiObject -Class Win32_BIOS -ComputerName .
#$user = Get-WmiObject -Class Win32_ComputerSystem
$last = Get-WmiObject -class Win32_NetworkLoginProfile |
Where {($_.NumberOfLogons -gt 0) -and ($_.NumberOfLogons -lt 65535)} |
Select-Object Name,#{label='LastLogon';expression={$_.ConvertToDateTime($_.LastLogon)}},NumberOfLogons
$props = #{
"Name" = $cpu.Name
"Description" = $cpu.Description
"MB Manufacturer" = $mb.Manufacturer
"MB Product" = $mb.Product
"Bios Verison" = $bios.SMBIOSBIOSVersion
"Bios Manufacturer" = $bios.Manufacturer
"Bios Serial" = $bios.SerialNumber
"~Last Logon" = $last
}
New-Object PSObject -Property $props | Out-File c:\Windows\Script\PS_Output3.xml
External IP Address
$wc=New-Object net.webclient;
$wc.downloadstring("http://checkip.dyndns.com") -replace "[^\d\.]"
Update
One last question: how could I organize the list?
Something like this might help:
#lists computer information
$cpu = Get-WmiObject -Class Win32_Processor
$mb = Get-WmiObject -Class Win32_BaseBoard
$bios = Get-WmiObject -Class Win32_BIOS -ComputerName .
#$user = Get-WmiObject -Class Win32_ComputerSystem
$DyDNS = Invoke-WebRequest http://checkip.dyndns.com/ -DisableKeepAlive
$Dyreg = $DyDNS.RawContent -match '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b'
$last = Get-WmiObject -class Win32_NetworkLoginProfile | Where {($_.NumberOfLogons -gt 0) -and ($_.NumberOfLogons -lt 65535)} | Select-Object Name,#{label='LastLogon';expression={$_.ConvertToDateTime($_.LastLogon)}},NumberOfLogons
$props = #{
"Name" = $cpu.Name
"Description" = $cpu.Description
"MB Manufacturer" = $mb.Manufacturer
"MB Product" = $mb.Product
"Bios Verison" = $bios.SMBIOSBIOSVersion
"Bios Manufacturer" = $bios.Manufacturer
"Bios Serial" = $bios.SerialNumber
"~Last Logon" = $last
"DNS" = $matches[0]
}
New-Object PSObject -Property $props | Out-File C:\test.csv

PowerShell add objects to body of email

I want to be able to collect information from this script and put it in the body of an email. For the most part it seems to work except I want serialnumber, osversion, model, loggedin on different lines in the body of the email.
[CmdletBinding()]
param (
$computername = (Read-Host "Enter Computer Name"),
$subject = 'Serial Numbers',
$to = 'test#test.com',
$bcc = 'test#test.com',
$body = $Collection,
#$body = (Get-Content -path "c:\powershell\serialnumber\SerialNumber.csv"),
#$mail = "mailto:$to&subject=$subject&body=$body",
[string]$ErrorLog = 'c:\powershell\useful\errorlog\retry.txt',
[switch]$LogErrors
)
[Array]$Collection = foreach($computer in $computername)
{
$os = Get-WmiObject `
Win32_OperatingSystem -computer $computer
$bios = Get-WmiObject `
Win32_BIOS -computer $computer
$model = Get-WmiObject `
Win32_ComputerSystem -computer $computer
$Monitor = Get-WmiObject -computer $computer WmiMonitorID -Namespace root\wmi |
ForEach-Object {($_.UserFriendlyName -notmatch 0 |
foreach {[char]$_}) -join ""; ($_.SerialNumberID -notmatch 0 |
foreach {[char]$_}) -join ""}
$body = New-Object -TypeName PSObject -Property #{
Computername = $computer;
LoggedIn = $Model.username;
OSVersion = $os.Caption;
SerialNumber = $bios.SerialNumber;
Model = $Model.Model;
Monitor = $Monitor;
}
#$obj | convertTo-csv | out-string
#$obj = $body
#$Collection = [string]$body
#[String]$Collection
[string]$body
Start-Process -FilePath "mailto:$to&bcc=$bcc&subject=$subject&body=$body"
}
$Collection
You can't use an object directly as the body of an email, it must be a [string]. Try this:
$body = New-Object -TypeName PSObject -Property #{
Computername = $computer;
LoggedIn = $Model.username;
OSVersion = $os.Caption;
SerialNumber = $bios.SerialNumber;
Model = $Model.Model;
Monitor = $Monitor;
} | format-list | out-string