Get Column values from text file - powershell

Below is the text file data I have
Disk ### Status Size Free Dyn Gpt
-------- ------------- ------- ------- --- ---
Disk 0 Online 100 GB 1024 KB
Disk 1 Online 6144 MB 1024 KB
Disk 2 Online 200 GB 1024 KB
Disk 3 Online 10 GB 1024 KB
I want to put this data in csv like below, removing the last 2 columns and adding the server value
server Disk ### Status Size Free
------ -------- ------------- ------- -------
s1 Disk 0 Online 100 GB 1024 KB
s1 Disk 1 Online 6144 MB 1024 KB
s1 Disk 2 Online 200 GB 1024 KB
s1 Disk 3 Online 10 GB 1024 KB
below is the code
$list = Get-Content -Path "C:\server.txt"
foreach($server in $list)
{
$diskpart = cmd /c 'echo list disk | diskpart'
}
$Lines = $diskpart
$Out = $False
$Line=#()
ForEach ($Line In $Lines)
{
If ($Line -match 'DISKPART>')
{
$Out = $False
}
If ($Out -eq $True)
{
$Line | Out-File "C:\d.txt" -Append
}
If ($Line -match 'DISKPART>')
{
$Out = $True
}
}
$data = Import-Csv -Path C:\d.txt
I tried reading line using foreach,but getting output with headers and ---
Disk ### Status Size Free Dyn Gpt
---------------------------------------------------
Disk 0 Online 100 GB 1024 KB
Please let me know how can I extract columns from text file and append the servername to it. Need some idea to do this

One way of converting this into a CSV file is like below.
Assuming you have the output from diskpart in a string array $lines and the current server is called 's1' :
$result = switch -Regex ($lines) {
'^\s*Disk \d' {
$disk,$status,$size,$free = $_.Trim() -split '\s{2,}'
[PsCustomObject]#{
'Server' = $server # 's1' in this example
'Disk ###' = $disk
'Status' = $status
'Size' = $size
'Free' = $free
}
}
}
# output on console screen
$result | Format-Table -AutoSize
# output to CSV file
$result | Export-Csv -Path 'C:\diskinfo.csv' -NoTypeInformation
Result on screen:
Server Disk ### Status Size Free
------ -------- ------ ---- ----
s1 Disk 0 Online 100 GB 1024 KB
s1 Disk 1 Online 6144 MB 1024 KB
s1 Disk 2 Online 200 GB 1024 KB
s1 Disk 3 Online 10 GB 1024 KB
P.S. It is strongly not recommended to use Out-File to build a CSV file. Use that only if other options are not available. To create CSV use Export-Csv
If you need to do this on a series of computers, you might use this:
$list = Get-Content -Path "C:\server.txt"
# parameter -ComputerName can handle an array of computer names at once
$lines = Invoke-Command -ComputerName $list -ScriptBlock { "list disk" | diskpart }
$result = switch -Regex ($lines) {
'^On computer: (\w+)' { $server = $Matches[1].Trim() }
'^\s*Disk \d' {
$disk,$status,$size,$free = $_.Trim() -split '\s{2,}'
[PsCustomObject]#{
'Server' = $server
'Disk ###' = $disk
'Status' = $status
'Size' = $size
'Free' = $free
}
}
}
# output on console screen
$result | Format-Table -AutoSize
# output to CSV file
$result | Export-Csv -Path 'C:\diskinfo.csv' -NoTypeInformation

Related

Write value only once in CSV using powershell

I am having the below code to write the data to csv
$myVMs = #(Get-VM -Server $vc | where {$_.PowerState -eq 'PoweredOn'} | select -Unique)
foreach ($myVM in $myVMs){
$VMDKs = $myVM | get-HardDisk
$VMDISKMode = $myVM
foreach ($VMDK in $VMDKs) {
if ($VMDK -ne $null){
$Diskmode = $VMDK.Persistence
if($Diskmode -ne 'Persistent')
{
$Report = [PSCustomObject] #{
Name = $myVM.name
Server = $vc
PowerState = $myVM.PowerState
Disk = $VMDK.Name
DiskMode = $VMDK.Persistence
}
$Report | Export-CSV -NoTypeInformation $File -Append
}
}
}
}
}
the output i am getting
Name Server PowerState Disk DiskMode
171_A92SV095 192.168.1.5 PoweredOn Hard disk 6 IndependentPersistent
171_A92SV095 192.168.1.5 PoweredOn Hard disk 7 IndependentPersistent
171_A92SV095 192.168.1.5 PoweredOn Hard disk 8 IndependentPersistent
171_A92SV095 192.168.1.5 PoweredOn Hard disk 10 IndependentPersistent
171_A92SV096 192.168.1.5 PoweredOn Hard disk 5 IndependentPersistent
171_A92SV096 192.168.1.5 PoweredOn Hard disk 10 IndependentPersistent
want the data like below
Name Server PowerState Disk DiskMode
171_A92SV095 192.168.1.5 PoweredOn Hard disk 6 IndependentPersistent
Hard disk 7
Hard disk 8
Hard disk 10
171_A92SV096 192.168.1.5 PoweredOn Hard disk 5 IndependentPersistent
Hard disk 10
Please let me know what changes I need to make in the code.
Taking the csv file you created with your code, you can use that as a basis to get the output you need like this:
$data = Import-Csv -Path 'D:\Test\VMInfo.csv'
# first group the data on the Name property
$data | Group-Object Name | ForEach-Object {
$name = $_.Name
# next, group that on property PowerState
foreach ($groupPowerState in ($_.Group | Group-Object PowerState)) {
$powerState = $groupPowerState.Name
# finally, group that on property DiskMode
foreach ($groupDiskMode in ($groupPowerState.Group | Group-Object DiskMode)) {
[PsCustomObject]#{
Name = $name
Server = $groupDiskMode.Group[0].Server
PowerState = $powerState
Disk = $groupDiskMode.Group.Disk -join [environment]::NewLine
DiskMode = $groupDiskMode.Name
}
}
}
} | Export-Csv -Path 'D:\Test\GroupedVMInfo.csv' -UseCulture -NoTypeInformation
This should give you a new CSV file you can double-click to open in Excel
Using your example data this would open in Excel as:
Of course, you don't need to write the report out to CSV and then read it back in if you would capture the output in variable $data like this:
$data = foreach ($myVM in $myVMs) {
$VMDKs = $myVM | Get-HardDisk
$VMDISKMode = $myVM
foreach ($VMDK in $VMDKs) {
if ($VMDK -ne $null) {
$Diskmode = $VMDK.Persistence
if($Diskmode -ne 'Persistent') {
[PSCustomObject] #{
Name = $myVM.name
Server = $vc
PowerState = $myVM.PowerState
Disk = $VMDK.Name
DiskMode = $VMDK.Persistence
}
}
}
}
}

Write Text file data to csv

Below is my data in text file
Volume ### Ltr Label Fs Type Size Status Info
---------- --- ----------- ----- ---------- ------- --------- --------
Volume 0 Z DVD-ROM 0 B No Media
Volume 1 System Rese NTFS Partition 500 MB Healthy System
Volume 2 C SYS NTFS Partition 99 GB Healthy Boot
Volume 3 S SWAP NTFS Partition 6141 MB Healthy Pagefile
Volume 4 D DATA NTFS Partition 199 GB Healthy
Volume 5 E bit locker NTFS Partition 9 GB Healthy
Volume 6 F test NTFS Partition 10 GB Healthy
I have to write it in csv. tried below code but not able to handle to Blank values. e.g. for first row Label,Fs,Info values are blank
$data = get-content -Path "C:\d.txt"
$result = switch -Regex ($data) {
'^\s*Volume \d' {
$disk,$status,$Label,$Fs,$Type,$size,$Stat,$Info = $_.Trim() -split '\s{2,}'
[PsCustomObject]#{
'Server' = $server
'Volume ###' = $disk
'Ltr' = $status
'Label' = $Label
'Fs' = $Fs
'Type' = $Type
'Size' = $size
'Status' = $Stat
'Info' = $Info
}
}
}
# output on console screen
$result | Format-Table -AutoSize
# output to CSV file
$result | Export-Csv -Path "C:\$server.csv" -NoTypeInformation -Append
Output is coming like
Server Volume ### Ltr Label Fs Type Size Status Info
------ ---------- --- ----- -- ---- ---- ------ ----
AxxxxxxxxxxxxxP Volume 0 Z DVD-ROM 0 B No Media
AxxxxxxxxxxxxxP Volume 1 System Rese NTFS Partition 500 MB Healthy System
AxxxxxxxxxxxxxP Volume 2 C SYS NTFS Partition 99 GB Healthy Boot
AxxxxxxxxxxxxxP Volume 3 S SWAP NTFS Partition 6141 MB Healthy Pagefile
AxxxxxxxxxxxxxP Volume 4 D DATA NTFS Partition 199 GB Healthy
AxxxxxxxxxxxxxP Volume 5 E bit locker NTFS Partition 9 GB Healthy
AxxxxxxxxxxxxxP Volume 6 F test NTFS Partition 10 GB Healthy
Please let me know how to handle the spaces or any other way I can write it to csv
After executing #Mathias code
"Count","IsReadOnly","Keys","Values","IsFixedSize","SyncRoot","IsSynchronized"
"9","False","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","False","System.Object","False"
"9","False","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","False","System.Object","False"
"9","False","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","False","System.Object","False"
"9","False","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","False","System.Object","False"
"9","False","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","False","System.Object","False"
"9","False","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","False","System.Object","False"
"9","False","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","False","System.Object","False"
"9","False","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","System.Collections.Specialized.OrderedDictionary+OrderedDictionaryKeyValueCollection","False","System.Object","False"
this is what I am trying to do
$server = $env:COMPUTERNAME
# Start by reading in the table
# Replace this statement with `
$lines = Get-Content "c:\d.txt"
$lines = $lines -split '\r?\n'
# Assign the first two lines to separate variables
$header, $guardRails, $lines = $lines
# Split the header into individual column names
$columnNames = #(
$header.Trim() -split '\s{2,}' |ForEach-Object Trim
)
# Use regex to match all the individual `---` sequences, grab their offset + length
$columnOffsets = #(
[regex]::Matches($guardRails, '(?<!-)-+(?!-)') |Select Index,Length
)
# Parse the data based on the offsets located above
foreach($line in $lines){
# Prepare a dictionary to hold the column values, add the Server property straight away
$properties = [ordered]#{
Server = $server
}
# Now we just need to iterate over the lists of column headers and extract the corresponding substring from the line
for($i = 0; $i -lt $columnNames.Length; $i++){
# Grab the column name and offset
$propertyName = $columnNames[$i]
$offset = $columnOffsets[$i]
# Grab the substring corresponding to the column
$propertyValue = $line.Substring($offset.Index, $offset.Length).Trim()
# Add the information to our property dictionary
$properties[$propertyName] = $propertyValue
}
# Output a new object based on the properties we grabbed from the column data
[pscustomobject]$properties
# output on console screen
$properties | Format-Table -AutoSize
# output to CSV file
$properties | Export-Csv -Path "C:\$server.csv" -NoTypeInformation -Append
}
Use the line below the header ( ---------- --- -----------...) to detect at which offsets to parse data for a specific column name:
# Start by reading in the table
# Replace this statement with `$lines = Get-Content .\path\to\file.txt` in your script
$lines = #'
Volume ### Ltr Label Fs Type Size Status Info
---------- --- ----------- ----- ---------- ------- --------- --------
Volume 0 Z DVD-ROM 0 B No Media
Volume 1 System Rese NTFS Partition 500 MB Healthy System
Volume 2 C SYS NTFS Partition 99 GB Healthy Boot
Volume 3 S SWAP NTFS Partition 6141 MB Healthy Pagefile
Volume 4 D DATA NTFS Partition 199 GB Healthy
Volume 5 E bit locker NTFS Partition 9 GB Healthy
Volume 6 F test NTFS Partition 10 GB Healthy
'# -split '\r?\n'
# Assign the first two lines to separate variables
$header, $guardRails, $lines = $lines
# Split the header into individual column names
$columnNames = #(
$header.Trim() -split '\s{2,}' |ForEach-Object Trim
)
# Use regex to match all the individual `---` sequences, grab their offset + length
$columnOffsets = #(
[regex]::Matches($guardRails, '(?<!-)-+(?!-)') |Select Index,Length
)
# Parse the data based on the offsets located above
$volumeInfo = foreach($line in $lines){
# Prepare a dictionary to hold the column values, add the Server property straight away
$properties = [ordered]#{
Server = 'Server123'
}
# Now we just need to iterate over the lists of column headers and extract the corresponding substring from the line
for($i = 0; $i -lt $columnNames.Length; $i++){
# Grab the column name and offset
$propertyName = $columnNames[$i]
$offset = $columnOffsets[$i]
# Grab the substring corresponding to the column
$propertyValue = $line.Substring($offset.Index, $offset.Length).Trim()
# Add the information to our property dictionary
$properties[$propertyName] = $propertyValue
}
# Output a new object based on the properties we grabbed from the column data
[pscustomobject]$properties
}
$volumeInfo |Export-Csv path\to\output.csv -NoTypeInformation

Combine `Get-Disk` info and `LogicalDisk` info in PowerShell (but with formatted output)

This is a question about an answer for this Combine `Get-Disk` info and `LogicalDisk` info in PowerShell?
Here is the answer which I've tried to change to get the output formatted how I want it:
https://stackoverflow.com/a/31092004/8262102
It needs to work for multiple drives like the code below only in the desired format.
This is the code with all the details on what my attempts are to do so:
$info_diskdrive_basic = 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 {
[PSCustomObject][Ordered]#{
Disk = $disk.DeviceID
DiskModel = $disk.Model
Partition = $partition.Name
RawSize = '{0:d} GB' -f [int]($partition.Size/1GB)
DriveLetter = $_.DeviceID
VolumeName = $_.VolumeName
Size = '{0:d} GB' -f [int]($_.Size/1GB)
FreeSpace = '{0:d} GB' -f [int]($_.FreeSpace/1GB)
}
}
}
}
# Here's my attempt at formatting the output of the code above.
# 1. This trims the dead whitespace from the output.
$info_diskdrive_basic = ($info_diskdrive_basic | Out-String) -replace '^\s+|\s+$', ('')
# 2. I then separate the DiskModel, RawSize, DriveLetter, VolumeName, FreeSpace with the regexp below so this becomes:
# Disk Model, Raw Size, Drive Letter, Volume Name, Free Space
$info_diskdrive_basic = ($info_diskdrive_basic) -replace '(?-i)(?=\B[A-Z][a-z])', (' ')
# 3. Here I then format the string to how I want:
$info_diskdrive_basic = ($info_diskdrive_basic) -replace '(.+?)(\s+):\s*(?!\S)', ($id2 + '$1:$2 ')
$info_diskdrive_basic
The output should look like this:
I want to format the properties and the values like so: Properties: >spaces< value where the value is over to the right and aligned along the left of them
# Disk: \\.\PHYSICALDRIVE0
# Disk Model: Crucial_CT512MX100SSD1
# Partition: Disk #0, Partition #2
# Raw Size: 476 GB
# Drive Letter: C:
# Volume Name:
# Size: 476 GB
# Free Space: 306 GB
But my output ends up like this: (Notice how the text is not aligned)
# Disk: \\.\PHYSICALDRIVE0
# Disk Model: Crucial_CT512MX100SSD1
# Partition: Disk #0, Partition #2
# Raw Size: 476 GB
# Drive Letter: C:
# Volume Name:
# Size: 476 GB
# Free Space: 306 GB
To output the info as you apparently need, we need to know the maximum line length (which in your example is 79 characters) and work our way from that.
$maxLineLength = 79 # counted from the longest line in your example
$maxValueLength = 0 # a counter to keep track of the largest value length in characters
$info_diskdrive_basic = 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 {
$obj = [PSCustomObject]#{
'Disk' = $disk.DeviceID
'Disk Model' = $disk.Model
'Partition' = $partition.Name
'Raw Size' = '{0:d} GB' -f [int]($partition.Size/1GB)
'Drive Letter' = $_.DeviceID
'Volume Name' = $_.VolumeName
'Size' = '{0:d} GB' -f [int]($_.Size/1GB)
'Free Space' = '{0:d} GB' -f [int]($_.FreeSpace/1GB)
}
# get the maximum length for all values
$len = ($obj.PsObject.Properties.Value.ToString().Trim() | Measure-Object -Property Length -Maximum).Maximum
$maxValueLength = [Math]::Max($maxValueLength, $len)
# output the object to be collected in $info_diskdrive_basic
$obj
}
}
}
# sort the returned array of objects on the DriveLetter property and loop through
$result = $info_diskdrive_basic | Sort-Object DriveLetter | ForEach-Object {
# loop through all the properties and calculate the padding needed for the output
$_.PsObject.Properties | ForEach-Object {
$label = '# {0}:' -f $_.Name.Trim()
$padding = $maxLineLength - $maxValueLength - $label.Length
# output a formatted line
"{0}{1,-$padding}{2}" -f $label, '', $_.Value.ToString().Trim()
}
# add a separator line between the disks
''
}
# output the result on screen
$result
# write to disk
$result | Set-Content -Path 'X:\theResult.txt'
# format for HTML mail:
'<pre>{0}</pre>' -f ($result -join '<br>')
Example output:
# Disk: \\.\PHYSICALDRIVE1
# Disk Model: Samsung SSD 750 EVO 250GB
# Partition: Disk #1, Partition #0
# Raw Size: 232 GB
# Drive Letter: C:
# Volume Name: System
# Size: 232 GB
# Free Space: 160 GB
# Disk: \\.\PHYSICALDRIVE2
# Disk Model: WDC WD7501AALS-00J7B0
# Partition: Disk #2, Partition #0
# Raw Size: 699 GB
# Drive Letter: D:
# Volume Name: Data
# Size: 699 GB
# Free Space: 385 GB
P.S. with creating [PsCustomObject], there is no need to add [Ordered]
Using your posted code as is, 'stringify' your properties
For example:
($info_diskdrive_basic = 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 {
[PSCustomObject][Ordered]#{
Disk = "$($disk.DeviceID)"
DiskModel = "$($disk.Model)"
Partition = "$($partition.Name)"
RawSize = "$('{0:d} GB' -f [int]($partition.Size/1GB))"
DriveLetter = "$($_.DeviceID)"
VolumeName = "$($_.VolumeName)"
Size = "$('{0:d} GB' -f [int]($_.Size/1GB))"
FreeSpace = "$('{0:d} GB' -f [int]($_.FreeSpace/1GB))"
}
}
}
})
# Results
<#
Disk : \\.\PHYSICALDRIVE0
DiskModel : Samsung SSD 950 PRO 512GB
Partition : Disk #0, Partition #0
RawSize : 477 GB
DriveLetter : D:
VolumeName : Data
Size : 477 GB
FreeSpace : 364 GB
...
#>
Point of note:
I am using PowerShell variable squeezing to assign the results to the variable and output to the screen at the same time.
Update
As for this...
"I want to format the properties and the values like so: Properties: >spaces< value"
$Spacer = ("`t")*8
($info_diskdrive_basic = 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 {
[PSCustomObject][Ordered]#{
Disk = "$Spacer$($disk.DeviceID)"
DiskModel = "$Spacer$($disk.Model)"
Partition = "$Spacer$($partition.Name)"
RawSize = "$Spacer$('{0:d} GB' -f [int]($partition.Size/1GB))"
DriveLetter = "$Spacer$($PSItem.DeviceID)"
VolumeName = "$Spacer$($PSItem.VolumeName)"
Size = "$Spacer$('{0:d} GB' -f [int]($PSItem.Size/1GB))"
FreeSpace = "$Spacer$('{0:d} GB' -f [int]($PSItem.FreeSpace/1GB))"
}
}
}
})
# Results
<#
Disk : \\.\PHYSICALDRIVE0
DiskModel : Samsung SSD 950 PRO 512GB
Partition : Disk #0, Partition #0
RawSize : 477 GB
DriveLetter : D:
VolumeName : Data
Size : 477 GB
FreeSpace : 364 GB
...
#>

Retrieving disk capacity with powershell

I made this code to count disk capacity, but when i run it with only the SSD in my laptop i get 0GB. after I insert USB/external space it count the ssd + the USB.
$disk = Get-WmiObject Win32_DiskDrive
$capacity = 0;
for($i = 0;$i -lt $disk.Count; $i++){
$capacity = $capacity + [math]::round(($disk[$i].Size/1GB),2)
}
Write-Host $capacity "GB"
This works fine -> $disk.Size
Why does it not take the first [0] in my for loop?
I cannot answer why your for loop is failing without observing your environment, but there is almost never a use-case for it. You should instead opt for a foreach loop:
$capacity = foreach ($disk in Get-WmiObject -Class Win32_DiskDrive)
{
[Math]::Round(($disk.Size / 1GB), 2)
}
"$(($capacity | Measure-Object -Sum).Sum)GB"
Assuming Windows 10 since you didn't mention OS and the CMDLETS in Windows 10 are so much better. *See at the bottom for a Windows 7 version.
For disk information, I prefer using Get-PhysicalDisk, like this for example:
$DiskInfo = foreach ($disk in Get-PhysicalDisk) {
[string]$name = $disk.FriendlyName
[string]$type = $disk.MediaType
[int]$capacity = $disk.size / 1GB
[pscustomobject]#{
"Type"=$type;
"Name"=$name;
"Capacity (GB)"=$capacity;
}
}
$DiskInfo
In my environement where I have one SSD and one mechanical HDD, it will return:
Name Type Capacity (GB)
---- ---- -------------
SAMSUNG MZ7TY256HDHP-000L7 SSD 238
ST500LX025-1U717D HDD 466
If you wanted information for JUST the SSD for example, you could do this :
$DiskInfo = foreach ($disk in Get-PhysicalDisk | Where-Object {$_.MediaType -eq "SSD"} ) {
[string]$name = $disk.FriendlyName
[string]$type = $disk.MediaType
[int]$capacity = $disk.size / 1GB
[pscustomobject]#{
"Type"=$type;
"Name"=$name;
"Capacity (GB)"=$capacity;
}
}
$DiskInfo
Which returns only the SSD:
Type Name Capacity (GB)
---- ---- -------------
SSD SAMSUNG MZ7TY256HDHP-000L7 238
Explanation: Foreach disk connected, store name, media type and capacity in variables. *Divide byte capacity by 1GB to get a better number to look at.
Still in the Foreach, create a custom object at every iteration containing the 3 variables.
All put together, you can then output your variable DiskInfo which contains all the objects.
If on Windows 7, media type isn't available so you can't use it. Instead you can do:
$DiskInfo = foreach ($disk in Get-WmiObject -Class Win32_DiskDrive) {
[string]$name = $disk.model
[int]$capacity = $disk.size / 1GB
[pscustomobject]#{
"Name"=$name;
"Capacity (GB)"=$capacity;
}
}
$DiskInfo
Which will return something like:
Name Capacity (GB)
---- -------------
SAMSUNG MZ7TY256HDHP-000L7 238
ST500LX025-1U717D 466

Using PowerShell to replicate right clicking a folder and selecting properties

I am trying to gather the Size/Size on disk and number of files/folders on a very large folder tree.
I have been using a script like the follow to gather some of this:
Get-ChildItem "C:\test" -recurse | Measure-Object -Sum Length | Select-Object `
#{Name="Path"; Expression={$directory.FullName}},
#{Name="Files"; Expression={$_.Count}},
#{Name="Size"; Expression={$_.Sum}}
Path Files Size
---- ----- ----
C:\test 470 11622961
But when I want to gather information on the number of folders and size on disk I'm having to run a separate script; which recuse through the folder tee again (Which takes a long time).
Is there an easy way of accessing the all this information the same way you can get it when you right click a folder and select properties shown below?
Are there any callable .exe files within system32 that can do this?
According to this answer in the Technet forums you can calculate the size on disk like this:
$afz = [MidpointRounding]::AwayFromZero
[math]::Round($_.Length / $clusterSize + 0.5, $afz) * $clusterSize
$clusterSize can be determined with the fsutil command (e.g. for drive C:):
PS C:\> fsutil fsinfo ntfsinfo C:\
NTFS Volume Serial Number : 0x648ac3ae16817308
Version : 3.1
Number Sectors : 0x00000000027ccfff
Total Clusters : 0x00000000004f99ff
Free Clusters : 0x0000000000158776
Total Reserved : 0x00000000000003e0
Bytes Per Sector : 512
Bytes Per Physical Sector : 512
Bytes Per Cluster : 4096
Bytes Per FileRecord Segment : 1024
Clusters Per FileRecord Segment : 0
...
Note that running fsutil requires admin privileges.
With that you can collect the information you're interested in like this:
$rootDir = "C:\test"
$afz = [MidpointRounding]::AwayFromZero
$clusterSize = fsutil fsinfo ntfsinfo (Get-Item $rootDir).PSDrive.Root `
| Select-String 'Bytes Per Cluster' `
| % { $_.ToString().Split(':')[1].Trim() }
$stat = Get-ChildItem $rootDir -Recurse -Force `
| select Name, Length, #{n="PhysicalSize";e={
[math]::Round($_.Length / $clusterSize + 0.5, $afz) * $clusterSize
}}, #{n="Folder";e={[int]($_.PSIsContainer)}},
#{n="File";e={[int](-not $_.PSIsContainer)}} `
| Measure-Object -Sum Length, PhysicalSize, Folder, File
$folder = New-Object -TypeName PSObject -Property #{
"FullName" = $rootDir;
"Files" = ($stat | ? { $_.Property -eq "File" }).Sum;
"Folders" = ($stat | ? { $_.Property -eq "Folder" }).Sum;
"Size" = ($stat | ? { $_.Property -eq "Length" }).Sum;
"SizeOnDisk" = ($stat | ? { $_.Property -eq "PhysicalSize" }).Sum - $clusterSize;
}
You're going to have to accumulate your data in a custom object as you see each item:
$path = "C:\Users\aaron\Projects\Carbon"
$properties = New-Object PsObject -Property #{ 'Path' = $path; 'Files' = 0; 'Folders' = 0; 'Size' = 0 }
Get-ChildItem -Path $path -Recurse |
ForEach-Object {
if( $_.PsIsContainer )
{
$properties.Folders++
}
else
{
$properties.Size += $_.Length
$properties.Files++
}
}
$properties