PC Inventory Powershell - powershell

$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

Related

Formatting multiple result sets together in powershell

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

powershell - remote disk information unique description

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"
}

Format results from a Get-WmiObject script to match list from get-content .txt file

I am trying to write a script that will get drive current drive space on our servers and return them to an output file.
Here is the script as of now:
$ServerName = Get-Content -Path "C:\Users\*****\Desktop\Testing Files\serverlist.txt"
Get-WmiObject Win32_LogicalDisk -ComputerName $ServerName -Filter DriveType=3 | Select-Object DeviceID, #{'Name'='Size (GB)'; 'Expression'={Expression'={[string]::Format('{0:NO}',[math]::truncate($_.size / 1GB))}}, #{'Name'='Freespace (GB)'; 'Expression'={[string]::Format('{0:NO}',[math]::truncate($_.freespace / 1GB))}}
Out-file "C:\users\xxxxxx\desktop\testing files\server space results.txt"
will not write to a text file; only displays results
The results display device ID, size (GB), freespace (GB) with no issues except one. Every drive is listed as C: and E: but does not split them up based on the device name so it is hard to tell which results go to which server. Below is a sample of the results of the script:
DeviceID Size (GB) Freespace (GB)
-------- --------- --------------
C: 58 13
E: 499 499
C: 79 30
E: 799 103
Any ideas?
You've got a few typos and/or syntax errors. Also if you want the Computer Name PowerShell adds the PSComputerName property:
$ServerName = Get-Content -Path "C:\Users\*****\Desktop\Testing Files\serverlist.txt"
Get-WmiObject Win32_LogicalDisk -ComputerName $ServerName -Filter DriveType=3 |
Select-Object PSComputerName,DeviceID,
#{'Name'='Size (GB)'; Expression = {[string]::Format('{0:N0}',[math]::truncate($_.size / 1GB))}},
#{'Name'='Freespace (GB)'; Expression = {[string]::Format('{0:N0}',[math]::truncate($_.freespace / 1GB))}} |
Out-file "C:\users\xxxxxx\desktop\testing files\server space results.txt"
Note: I prefer to use win32_Volume instead. Also you should think about using Get-CimInstance instead of Get-WMIObject. The latter is deprecated.
Update
Here's a slightly modified version. I typically use [Math]::Round() in these cases. It will keep the value numeric so it aligns right.
$ServerName = Get-Content -Path "C:\Users\*****\Desktop\Testing Files\serverlist.txt"
Get-WmiObject Win32_LogicalDisk -ComputerName $ServerName -Filter DriveType=3 |
Select-Object PSComputerName,DeviceID,
#{'Name'='Size (GB)'; Expression = { [Math]::Round( ($_.size / 1GB), 0 ) } },
#{'Name'='Freespace (GB)'; Expression = { [Math]::Round( ($_.freespace / 1GB), 0 ) } } |
Out-file "C:\temp\xxxxxx\desktop\testing files\server space results.txt"

Powershell Script to check C: drive capacity and write to CSV file

I'm trying to get C:\ total size and the free space, but it is not appending to CSV file.
Tried using DeviceID and Devicetype, not sure which one is true
$path="C:\server" #Split-Path $MyInvocation.MyCommand.path 
#$cred= get-credential 
$Computers = get-content "$path\computers.txt"   
foreach ($Computer in $Computers)  
{  
$Disks = Get-wmiobject  Win32_LogicalDisk -computername $Computer
}
this will do what i think you want. i am still unsure what your actual problem is since you did not include all the code that you referred to.
i THINK the problem you were referring to was how to ID the system drive. i got the drive letter from Get-CimInstance -ClassName CIM_OperatingSystem and then used that to filter the results from a call to Get-CimInstance -ClassName CIM_LogicalDisk.
i've only one system, so the responses are all from that one. [grin]
#requires -RunAsAdministrator
# fake reading in a list of computers from a text file
# in real life, use Get-Content
$ComputerList = #'
LocalHost
BetterNotBeThere
127.0.0.1
10.0.0.1
'# -split [environment]::NewLine
$IC_Scriptblock = {
$CIM_ComputerSystem = Get-CimInstance -ClassName CIM_ComputerSystem
$CIM_OperatingSystem = Get-CimInstance -ClassName CIM_OperatingSystem
$CIM_LogicalDisk = Get-CimInstance -ClassName CIM_LogicalDisk |
Where-Object {$_.Name -eq $CIM_OperatingSystem.SystemDrive}
[PSCustomObject]#{
ComputerName = $CIM_ComputerSystem.Name
SysDrive = $CIM_OperatingSystem.SystemDrive
SysDrive_FreeSpace_GB = '{0:N2}' -f ($CIM_LogicalDisk.FreeSpace / 1GB)
SysDrive_FreeSpace_Pct = '{0:N0}' -f (($CIM_LogicalDisk.FreeSpace / $CIM_LogicalDisk.Size) * 100)
SysDrive_Size_GB = '{0:N2}' -f ($CIM_LogicalDisk.Size / 1GB)
}
}
$RespondingSystems = foreach ($CL_Item in $ComputerList)
{
$IC_Params = #{
ComputerName = $CL_Item
ScriptBlock = $IC_Scriptblock
ErrorAction = 'SilentlyContinue'
}
Invoke-Command #IC_Params
}
$NON_RespondingSystems = $ComputerList.Where({$_ -notin $RespondingSystems.PSComputerName})
$RespondingSystems
'=' * 30
$NON_RespondingSystems
# send to CSV
# this also removes the PSComputerName, PSShowComputerName, & RunspaceId properties
$RespondingSystems |
Select-Object -Property * -ExcludeProperty PSComputerName, PSShowComputerName, RunspaceId |
Export-Csv -LiteralPath "$env:TEMP\Zee_SysDriveInfo.csv" -NoTypeInformation
on screen output ...
ComputerName : [MySystemName]
SysDrive : C:
SysDrive_FreeSpace_GB : 747.75
SysDrive_FreeSpace_Pct : 80
SysDrive_Size_GB : 931.41
PSComputerName : LocalHost
RunspaceId : e09d14e9-448b-4e0e-99c1-95e9c636963b
ComputerName : [MySystemName]
SysDrive : C:
SysDrive_FreeSpace_GB : 747.75
SysDrive_FreeSpace_Pct : 80
SysDrive_Size_GB : 931.41
PSComputerName : 127.0.0.1
RunspaceId : ece90fac-5f1d-4f27-8685-5e4955e306b8
==============================
BetterNotBeThere
10.0.0.1
CSV file content ...
"ComputerName","SysDrive","SysDrive_FreeSpace_GB","SysDrive_FreeSpace_Pct","SysDrive_Size_GB"
"[MySystemName]","C:","747.75","80","931.41"
"[MySystemName]","C:","747.75","80","931.41"

Correlate Physical Device ID to Volume Device ID

I'm trying to utilize WMI via PowerShell to run through SAN storage on remote servers to grab the Windows disk management volume label.
The only way I've found to do this is to correlate the volume device id (\\?\Volume{34243...} with the physical disk device ID (\\.\PHYSICALDRIVE01).
However, I haven't been able to find out how to link those two fields together. Is this possible with WMI?
For volumes that were assigned a drive letter you can correlate disks and volumes like this:
Get-WmiObject Win32_DiskDrive | ForEach-Object {
$disk = $_
$partitions = "ASSOCIATORS OF " +
"{Win32_DiskDrive.DeviceID='$($disk.DeviceID)'} " +
"WHERE AssocClass = Win32_DiskDriveToDiskPartition"
Get-WmiObject -Query $partitions | ForEach-Object {
$partition = $_
$drives = "ASSOCIATORS OF " +
"{Win32_DiskPartition.DeviceID='$($partition.DeviceID)'} " +
"WHERE AssocClass = Win32_LogicalDiskToPartition"
Get-WmiObject -Query $drives | ForEach-Object {
$driveLetter = $_.DeviceID
$fltr = "DriveLetter='$driveLetter'"
New-Object -Type PSCustomObject -Property #{
Disk = $disk.DeviceID
DriveLetter = $driveLetter
VolumeName = $_.VolumeName
VolumeID = Get-WmiObject -Class Win32_Volume -Filter $fltr |
Select-Object -Expand DeviceID
}
}
}
}
Otherwise it doesn't seem possible with WMI.
On Windows 8/Server 2012 or newer you could use the Get-Partition cmdlet, though:
Get-Partition | Select-Object DiskNumber, DriveLetter, #{n='VolumeID';e={
$_.AccessPaths | Where-Object { $_ -like '\\?\volume*' }
}}
I have done a script that collects the most important stuff from volume and disk WMI. its used with getting information from a Remote Desktop server where a lot of disks are mounted but can be hard to find who is using which disk. its using AD to query the user and connect it with the SID to find the file path. so its a matter of first collecting all the data from the different disk commands and then combine the outputs. the most important command to bind disk data with volume data is the get-partition that shows deviceid
Function Get-VHDMount {
[cmdletbinding()]
Param(
[Parameter(Position=0,ValueFromPipeline=$True)]
[ValidateNotNullorEmpty()]
[OBJECT[]]$Computername,
[STRING]$RDSPATH = '\\rdsprofiles'
)
foreach ($computer in $Computername) {
$RDSItems = (Get-ChildItem $RDSPATH -Recurse -Filter *.vhdx)
$VolumeInfo = invoke-command -ComputerName $computer -scriptblock {Get-Volume | select *}
$VHDMountInfo = Get-WmiObject Win32_Volume -ComputerName $computer |where Label -eq 'user Disk'
$partitioninfo = invoke-command -ComputerName $computer -scriptblock {Get-Partition | Select-Object DiskNumber, #{n='VolumeID';e={$_.AccessPaths | Where-Object { $_ -like '\\?\volume*' }}}}
foreach ($VHDmount in $VHDMountInfo) {
$adinfo = Get-ADUser ($VHDmount.name | Split-Path -Leaf)
[PSCUSTOMOBJECT]#{
Computername = $computer
username = $VHDmount.name | Split-Path -Leaf
displayname = $adinfo.name
SID = $adinfo.SID
deviceid = $VHDmount.deviceid
capacity = ([MATH]::ROUND(($VHDmount.capacity) / 1gb))
HealthStatus = ($VolumeInfo | where ObjectId -eq ($VHDmount.deviceid)).HealthStatus
DiskNumber = ($partitioninfo | where Volumeid -eq ($VHDmount.deviceid)).DiskNumber
Path = ($RDSItems | where fullname -like "*$($adinfo.SID)*").FullName
}
}
}
}