Need some assistance with the below script created, i can create a HTML report of the disk space for all remote machines i specified; however how do i add a meaningful description for each host i.e the pic below.
Script below
$Machine = #("Fakehost1", "Fakehost2", "fakehost3")
Get-CimInstance Win32_LogicalDisk -ComputerName $Machine -Filter "DriveType = '3'" -ErrorAction SilentlyContinue |
Select-Object PsComputerName, DeviceID,
#{N="Disk Size (GB) "; e={[math]::Round($($_.Size) / 1073741824,0)}},
#{N="Free Space (GB)"; e={[math]::Round($($_.FreeSpace) / 1073741824,0)}},
#{N="Free Space (%)"; e={[math]::Round($($_.FreeSpace) / $_.Size * 100,1)}} |
Sort-Object -Property 'Free Space (%)' |
ConvertTo-Html -Head $Head -Title "$Title" -PreContent "<p><font size=`"6`">$Title</font><p>Generated on $date</font></p>" > $HTML
A quick fix is to Sruce up the PSComputerName object in the same Select-Object command. You're already doing a lot of calculated properties what's 1 more...
Get-CimInstance Win32_LogicalDisk -ComputerName $Machine -Filter "DriveType = '3'" -ErrorAction SilentlyContinue |
Select-Object #{N = 'PSComputerName'; E = { $_.PSComputerName + " : Description" }},
DeviceID,
#{N="Disk Size (GB) ";e={[math]::Round($($_.Size) / 1073741824,0)}},
#{N="Free Space (GB)";e={[math]::Round($($_.FreeSpace) / 1073741824,0)}},
#{N="Free Space (%)";e={[math]::Round($($_.FreeSpace) / $_.Size * 100,1)}} |
Sort-Object -Property 'Free Space (%)' |
ConvertTo-Html -Head $Head -Title "$Title" -PreContent "<p><font size=`"6`">$Title</font><p>Generated on $date</font></p>" > $HTML
This tested good in my environment, but you will have to decide how to or what the actual description should be... If you are in an AD environment maybe you can create a hash to hold the descriptions like:
$Descriptions = #{}
$Machine |
Get-ADComputer -Properties Description |
ForEach-Object{ $Descriptions.Add( $_.Name, $_.Description ) }
Then change the PSComputerName expression like:
#{N = 'PSComputerName'; E = { $_.PSComputerName + $Descriptions[$_.PSComputerName] }}
This would reference the hash and return the value you got from the AD description attribute. Of course, that means the attribute has to be populated. But it's just 1 idea to demonstrate the point that the description must be mined from somewhere.
Update:
To answer your comment, You could manually specify the hash instead. use something like below, before the Get-CimInstance command. Make sure to remove the previous AD stuff...
$Descriptions =
#{
Fakehost1 = "SQL Server for some bug app..."
Fakehost2 = "File Server 1"
Fakehost3 = "Another file server"
}
Related
Get-WmiObject -Class Win32_OperatingSystem -ComputerName (Get-Content "C:\Temp\Servers.txt") | SELECT-Object PSComputerName, #{Name="Memory (RAM in GB)";Expression={[Math]::Round($_.TotalVisibleMemorySize/1024/1024)}} | Format-Table
Get-WmiObject -Class Win32_logicaldisk -ComputerName (Get-Content "C:\Temp\Servers.txt") | Select-Object PSComputerName, DriveType, DeviceID, VolumeName, #{Name="Size";Expression={[math]::ceiling($_.Size /1GB)}} , #{Name="FreeSpace";Expression={[math]::ceiling($_.FreeSpace /1GB)}}, Compressed | where DriveType -eq 3 | Format-Table
Get-WmiObject -Class Win32_OperatingSystem -ComputerName (Get-Content "C:\Temp\Servers.txt")| Select-Object PSComputerName, BuildNumber, BuildType, Caption, CodeSet, OSArchitecture, SystemDrive, TotalVisibleMemorySize, Version | Format-Table
Get-WmiObject -Class win32_product -ComputerName (Get-Content "C:\Temp\Servers.txt") | Select-Object Name, Version, Vendor, InstallDate | Format-Table
Get-WmiObject -Class Win32_Service -ComputerName (Get-Content "C:\Temp\Servers.txt") | Select-Object PSComputerName, DisplayName, StartName, PathName, StartMode| where DisplayName -Like "*xyz*" |Format-Table
I have till now managed to piece together the above to get the information I need from serveral servers, however now I want to format it so that I can collate information for each server in a format that I can display
for eg.
Server : ABC
RAM : 64 GB
Number of Processors : 8
Disk :
Table of disk Sizes Etc
Any pointers would be appreciated
With all these properties, you would get a nested object array, which probably is easiest to view in JSON format.
I have changed all Get-WmiObject into the newer and faster Get-CimInstance cmdlets below
$result = Get-Content "C:\Temp\Servers.txt" | ForEach-Object {
# create an ordered hashtable to store the results for each server
$pcinfo = [ordered]#{}
# System info
$data = Get-CimInstance -ClassName Win32_ComputerSystem -ComputerName $_
$pcinfo['Computer'] = $data.PSComputerName
$pcinfo['Memory (RAM in GB)'] = '{0:N2}' -f ($data.TotalPhysicalMemory / 1GB)
# OS info
$data = Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName $_
$pcinfo['BuildNumber'] = $data.BuildNumber
$pcinfo['BuildType'] = $data.BuildType
$pcinfo['Caption'] = $data.Caption
$pcinfo['CodeSet'] = $data.CodeSet
$pcinfo['OSArchitecture'] = $data.OSArchitecture
$pcinfo['SystemDrive'] = $data.SystemDrive
$pcinfo['TotalVisibleMemorySize'] = $data.TotalVisibleMemorySize
$pcinfo['Version'] = $data.Version
# Product info (array of objects)
$pcinfo['Products'] = Get-CimInstance -ClassName Win32_Product -ComputerName $_ |
Select-Object Name, Version, Vendor, InstallDate
# Local fixed disk info (array of objects)
$pcinfo['FixedDrives'] = Get-CimInstance -ClassName Win32_LogicalDisk -ComputerName $_ -Filter 'DriveType=3' |
Sort-Object DeviceID |
Select-Object DriveType, DeviceID, VolumeName,
#{Name="Size";Expression={"{0:N2} GB" -f ($_.Size / 1GB)}},
#{Name="FreeSpace";Expression={"{0:N2} GB" -f ($_.FreeSpace / 1GB)}},
Compressed
# Services info (array of objects)
$pcinfo['Services'] = Get-CimInstance -ClassName Win32_Service -ComputerName $_ |
Where-Object { $_.DisplayName -like '*Adobe*' } |
Select-Object DisplayName, StartName, PathName, StartMode
# convert the hashtable to PSObject and output
[PsCustomObject]$pcinfo
}
# output the whole structure as JSON for easier reading and optionally save it to file
$result | ConvertTo-Json -Depth 3 # | Set-Content -Path 'Path\To\Output.json' -Force
$output.'AvailableDriveSpace (GB)' = Get-CimInstance -ComputerName $server -ClassName Win32_LogicalDisk |
Select-Object -Property DeviceID,#{Name='FreeSpace';Expression={ [Math]::Round(($_.Freespace / 1GB),1) }}
When running the script I built, I get all the correct information but it's displayed like this below
Processor : Intel(R) Core(TM) i5-7500 CPU # 3.40GHz
OperatingSystem : Microsoft Windows 10 Pro
AvailableDriveSpace (GB) : {#{DeviceID=C:; FreeSpace=4.9}, #{DeviceID=D:; FreeSpace=0}, #{DeviceID=H:; FreeSpace=194.7}, #{DeviceID=S:; FreeSpace=215.6}}
RAM (GB) : 8
UserProfileSize (GB) : 17
Any ideas how I can get it more user friendly :)
It all depends on what you think is a more user friendly output.
Perhaps something like this is what you're after?
$output = [PsCustomObject]#{
'Processor' = (Get-CimInstance -ClassName Win32_Processor -ComputerName $Computer).Name -replace '\s+', ' '
'OperatingSystem' = (Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName $Computer).Caption.Trim()
'AvailableDriveSpace (GB)' = (Get-CimInstance -ClassName Win32_LogicalDisk -ComputerName $Computer | ForEach-Object {
'DeviceID = {0} FreeSpace = {1}' -f $_.DeviceId, [Math]::Round(($_.Freespace / 1GB),1)
} ) -join ([Environment]::NewLine)
# get the user name who last logged on. The Where-Object clause filters out
# NT AUTHORITY\SYSTEM, NT AUTHORITY\LOCAL SERVICE etc.
'LastLogOn' = (Get-CimInstance -ClassName Win32_NetworkLoginProfile -ComputerName $Computer |
Where-Object { $_.Name -notlike 'NT AUTHORITY*' } |
ForEach-Object {
'UserName = {0} LastLogon = {1}' -f $_.Name, $_.LastLogon
} ) -join ([Environment]::NewLine)
}
$output | fl *
Result:
Processor : Intel(R) Core(TM) i5-7500 CPU # 3.40GHz
OperatingSystem : Microsoft Windows 10 Pro
AvailableDriveSpace (GB) : DeviceID = C: FreeSpace = 86
DeviceID = D: FreeSpace = 390.3
DeviceID = E: FreeSpace = 313
DeviceID = F: FreeSpace = 0
DeviceID = G: FreeSpace = 0
LastLogOn : UserName = Domain\User LastLogon = 12/16/2019 08:37:48
You could convert the object returned by the Get-CimInstance cmdlet to a string by using Foreach-Object:
Get-CimInstance -ComputerName $server -ClassName Win32_LogicalDisk |
Select-Object -Property DeviceID,#{Name='FreeSpace';Expression={ [Math]::Round(($_.Freespace / 1GB),1) }} |
Foreach-Object{$AvailSpace += $_.DeviceId + " (" + $_.FreeSpace + " available) "}
You can then set the $output.'AvailableDriveSpace (GB)' attribute to the $AvailSpace string created in the Foreach-Object cmdlet.
You need to manually construct a friendly string representation of the array stored in .AvailableDriveSpace (GB), which can you do as part of an explicit Format-List (or Format-Table) call:
./yourScript.ps1 |
Format-List Processor,
OperatingSystem,
#{
n='AvailableDriveSpace (GB)'
e={
$_.'AvailableDriveSpace (GB)'.ForEach({
'{0}={1}' -f $_.DeviceId, $_.FreeSpace
}) -join ' '
}
},
'RAM (GB)',
'UserProfileSize (GB)'
The above yields something like:
...
AvailableDriveSpace (GB) : C:=4.9 D:=0 H:=194.7 S:=215.6
...
Note that if you want your script itself to output this representation, you have the following options:
Construct your object with the friendly string to begin with, instead of the structured, array-valued AvailableDriveSpace (GB) property, as shown in Theo's answer. If you don't need to programmatically process this property further, this may be acceptable.
Otherwise, you'll have to give your output objects a self-chosen ETS type name and create format data for that virtual type beforehand, which allows you to control the default for-display formatting; note however, that that is a nontrivial effort - see about_Format.ps1xml
Not sure how to explain this, we're doing an assessment on disk usage on Azure, to reduce costs. We are trying to asses the space on each vm and reduce the disks
I'd like to add a recommendation column in there based on the free space, if the freespace is greater than 90% then add a comment "consider resizing" if less than 15% then "consider disk clean up".
The script I have works fine except it doesn't add the comment in, first I tried this...
$computers = (Get-AdComputer -Filter "name -like 'VM-*'").Name | Sort-Object
foreach ($computer in $Computers)
{
$vol = gwmi Win32_volume -Computer $Computer -Filter 'DriveType = 3'
#$vol
$info = $vol | select PsComputerName, DriveLetter, Label,
#{n='Capacity';e={[int]($_.capacity/1GB)}},
#{n='FreeSpace';e={[int]($_.FreeSpace/1GB)}},
#{n='FreeSpace (%)';e={[int](($_.FreeSpace) / ($_.capacity) * 100.0)}}
if ('FreeSpace (%)' -gt 85)
{
Write-Output "Disk Usage Low, Consider Resizing Options"
}
else
{
Write-Output "Disk Usage High"
}
$info | Export-Csv "c:\temp\tempfiles\question.csv" -Append
}
That didn't work, I then tried adding another section, where I get true or false, which seems to work.. that one is below, however I need to dd recommendations in..
$computers = (Get-AdComputer -Filter "name -like 'VM-*'").Name | Sort-Object
foreach ($computer in $Computers)
{
$vol = gwmi Win32_volume -Computer $Computer -Filter 'DriveType = 3'
#$vol
$info = $vol | select PsComputerName, DriveLetter, Label,
#{n='Capacity';e={[int]($_.capacity/1GB)}},
#{n='FreeSpace';e={[int]($_.FreeSpace/1GB)}},
#{n='FreeSpace (%)';e={[int](($_.FreeSpace) / ($_.capacity) * 100.0)}},
#{n='Recommendation';e={[String] ($_.FreeSpace -gt 90)}}
$info | Export-Csv "c:\temp\tempfiles\question.csv" -Append
}
Hope that makes sense.
Thanks in advance :)
The e stands for Expression. So you should be able to use an expression in there, using the original object properties (i.e. not your custom property names such as FreeSpace (%))
$computers = (Get-AdComputer -Filter "name -like 'VM-*'").Name | Sort-Object
foreach ($computer in $Computers)
{
$vol = gwmi Win32_volume -Computer $Computer -Filter 'DriveType = 3'
#$vol
$info = $vol | select PsComputerName, DriveLetter, Label,
#{n='Capacity';e={[int]($_.capacity/1GB)}},
#{n='FreeSpace';e={[int]($_.FreeSpace/1GB)}},
#{n='FreeSpace (%)';e={[int](($_.FreeSpace) / ($_.capacity) * 100.0)}},
#{n='Recommendation';e={
if((($_.FreeSpace) / ($_.capacity) * 100.0) -gt 90){
"Disk Usage Low, Consider Resizing Options"
}elseif((($_.FreeSpace) / ($_.capacity) * 100.0) -gt 75){
"Something else"
}else{
"Disk Usage High"
}
}
$info | Export-Csv "c:\temp\tempfiles\question.csv" -Append
}
**I tried n "n" '`n'
Blockquote
**
GC D:\code\ServerList.txt | % {
$Comp = $_
#write-output "server Information"
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 #{
"ServerInfo" = ""
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)) %"
"Total FreeSpace" = "$("{0:N2}" -f ((Get-WmiObject -Class
win32_logicaldisk -ComputerName $COMP -Filter "DriveType = '3'" |
Measure-Object -property FreeSpace -Sum).Sum /1GB)) GB"
"DiskSpace" = "$("{0:N2}" -f ((Get-WmiObject -Class
win32_logicaldisk -ComputerName $COMP -Filter "DriveType = '3'" |
Measure-Object -property Size -Sum).Sum /1GB)) GB"
"Comment" = ""
"logged Users" = $Luser
}
}
Else{
"" | Select #{N="Server";E={$Comp}},"CPU usage","Memory usage","Total
FreeSpace","logged Users","DiskSpace"
}
}| Select "ServerInfo",Server,"logged Users","CPU usage","Memory
usage","Total FreeSpace" ,"DiskSpace", "Comment" |
Export-Csv "D:\code\Diskncpu.csv" -nti –Append
output
desired output
"`r`n"
Needs to be in double quotes I believe.
Use [System.Environment]::NewLine to add new lines anywhere you need.
Having said that I formatted your code for clarity and executed against an array
#("MECDEVAPP01","MECDEVAPP01")| % {
$Comp = $_
#write-output "server Information"
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 #{
"ServerInfo" = ""
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)) %"
"Total FreeSpace" = "$("{0:N2}" -f ((Get-WmiObject -Class win32_logicaldisk -ComputerName $COMP -Filter "DriveType = '3'" | Measure-Object -property FreeSpace -Sum).Sum /1GB)) GB"
"DiskSpace" = "$("{0:N2}" -f ((Get-WmiObject -Class win32_logicaldisk -ComputerName $COMP -Filter "DriveType = '3'" | Measure-Object -property Size -Sum).Sum /1GB)) GB"
"Comment" = ""
"logged Users" = $Luser
}
}
Else{
"" | Select #{N="Server";E={$Comp}},"CPU usage","Memory usage","Total FreeSpace","logged Users","DiskSpace"
}
}| Select "ServerInfo",Server,"logged Users","CPU usage","Memory usage","Total FreeSpace" ,"DiskSpace", "Comment"|
Export-Csv "C:\Users\asarafian\Downloads\Diskncpu.csv" -nti –Append
The csv file is like this
"ServerInfo","Server","logged Users","CPU usage","Memory usage","Total FreeSpace","DiskSpace","Comment"
"","MECDEVAPP01","","7 %","70,24 %","203,97 GB","278,36 GB",""
"","MECDEVAPP01","","0 %","70,25 %","203,97 GB","278,36 GB",""
which is what I would expect from a conversion of a recordset (that's what you are building with all those pipes) into a csv.
I you want to product a formatted text then you cant use csv or you need to combine elements of it.
Try using `r`n for a new line. It needs the new line and carriage return to work.
If I understand you correctly you want a row to appear with a newline character, but instead you get the `r`n litteral characters or anything you try to throw at it.
Minimal testcase I can come up with to reproduce this problem:
> function paste ($separator = '`r`n') {$($input) -join $separator}
> & { echo foo; echo bar; echo baz; } | paste
foo`r`nbar`r`nbaz
Expceted result was
foo
bar
baz
How do you get actual newlines as output instead of literal `r`n? Super simple, just use the suggested answer!
> function paste ($separator = "`r`n") {$($input) -join $separator}
> & { echo foo; echo bar; echo baz; } | paste
foo
bar
baz
Or, if you do not like magic strings:
function paste ($separator = [System.Environment]::NewLine) {$($input) -join $separator}
PS D:\Temp\specs\ProRail.TrackChanges.Specs.Features> & { echo foo; echo bar; echo baz; } | paste
foo
bar
baz
This question already has answers here:
Change order of columns in the object
(5 answers)
Closed 5 years ago.
Good Afternoon,
I have the following script to generate a table as part of a html report that I have:
(import-csv "C:\AutoTasks\server.txt" |
% {new-object psobject -property #{
"Asset Number"=$_.Computer;
"Region"=$_.Description;
"Online Status"=(test-connection -computername $_.Computer -quiet -count 1);
"Online Since"= Try {(([Management.ManagementDateTimeConverter]::ToDateTime((gwmi Win32_OperatingSystem -ComputerName $_.Computer -ErrorAction Stop).LastBootUpTime)))} Catch {"Offline"} ;
"Service"=((Get-Service -ComputerName $_.Computer | Where-Object {$_.DisplayName -eq "ServiceName"}).Status);
"Disk Size (GB)" = ([Math]::Round(((get-WmiObject win32_logicaldisk -Computername $_.Computer -Filter $_.Drive).size)/1Gb,2));
"Free Disk Space (GB)" = ([Math]::Round(((get-WmiObject win32_logicaldisk -Computername $_.Computer -Filter $_.Drive).freespace)/1Gb,2));
"Free Disk Space %" = ([Math]::Round(100*(([Math]::Round(((get-WmiObject win32_logicaldisk -Computername $_.Computer -Filter $_.Drive).freespace)/1Gb,2)) / ([Math]::Round(((get-WmiObject win32_logicaldisk -Computername $_.Computer -Filter $_.Drive).size)/1Gb,2))),2))
}} | ConvertTo-HTML -as Table -Fragment -PreContent "<h2>Backup Machines</h2>" | Out-String)
It does everything I need.
However, my issue is with the column ordering. It doesn't display in the column order I've listed, and there is seemingly no logic behind the order it offers.
Any ideas how I can specify the order, am I missing a format-table statement somewhere? My searches are drawing a blank.
In PowerShell 3.0 and newer, you can use the [ordered] attribute on a hashtable literal to indicate that you want an ordered dictionary instead:
(import-csv "C:\AutoTasks\server.txt" |
% {new-object psobject -property $([ordered]#{
"Asset Number"=$_.Computer;
"Region"=$_.Description;
"Online Status"=(test-connection -computername $_.Computer -quiet -count 1);
"Online Since"= Try {(([Management.ManagementDateTimeConverter]::ToDateTime((gwmi Win32_OperatingSystem -ComputerName $_.Computer -ErrorAction Stop).LastBootUpTime)))} Catch {"Offline"} ;
"Service"=((Get-Service -ComputerName $_.Computer | Where-Object {$_.DisplayName -eq "ServiceName"}).Status);
"Disk Size (GB)" = ([Math]::Round(((get-WmiObject win32_logicaldisk -Computername $_.Computer -Filter $_.Drive).size)/1Gb,2));
"Free Disk Space (GB)" = ([Math]::Round(((get-WmiObject win32_logicaldisk -Computername $_.Computer -Filter $_.Drive).freespace)/1Gb,2));
"Free Disk Space %" = ([Math]::Round(100*(([Math]::Round(((get-WmiObject win32_logicaldisk -Computername $_.Computer -Filter $_.Drive).freespace)/1Gb,2)) / ([Math]::Round(((get-WmiObject win32_logicaldisk -Computername $_.Computer -Filter $_.Drive).size)/1Gb,2))),2))
})} | ConvertTo-HTML -as Table -Fragment -PreContent "<h2>Backup Machines</h2>" | Out-String)