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

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"

Related

Apply filter to Test-NetConnection result pipeline

I'm trying to create simple "ping" job using PowerShell. And I want to do it in "pipeline" way. Though it looks like Where-Object receives strings, not objects of TestNetConnectionResult class. Could you please explain how to filter out the results of Test-NetConnection where ping was successful?
Get-Content .\adresses.txt | Test-NetConnection | Where-Object { $_.PingSucceeded } | Write-Output
The filter is working correctly but you need a final ForEach-Object for processing results in the pipeline.
Get-Content .\adresses.txt `
| Test-NetConnection `
| Where-Object { $_.PingSucceeded } `
| ForEach-Object { Write-Host "SUCCEDED: $($_.ComputerName)" }
Note: if you also want to silent warnings from Test-NetConnection please check this question.
function megaPing {
[CmdletBinding()]
Param(
[Parameter(ValueFromPipeline, Mandatory, Position = 0)]
[string]$serverName
)
process {
, [PSCustomObject]#{
serverName = $serverName
PingSucceeded = (Test-NetConnection $serverName).PingSucceeded
}
}
}
"127.0.0.1", "127.0.0.2" | megaPing
You need use pipe lines
Here's another approach:
Get-Content -Path '.\adresses.txt' | Test-NetConnection |
Select-Object #{Name = 'Address'; Expression = {$_.ComputerName}},
#{Name = 'PingSucceeded'; Expression = {$_.PingSucceeded}}
If you don't want the Progress bar, do this:
$oldProgress = $ProgressPreference
$ProgressPreference = 'SilentlyContinue'
Get-Content -Path '.\adresses.txt' | Test-NetConnection |
Select-Object #{Name = 'Address'; Expression = {$_.ComputerName}},
#{Name = 'PingSucceeded'; Expression = {$_.PingSucceeded}}
$ProgressPreference = $oldProgress
Result will look something like
Address PingSucceeded
--------- -------------
127.0.0.1 True
10.10.2.153 False
Ignore warnings? Warnings wouldn't put objects in the pipeline anyway.
echo yahoo.com microsoft.com | set-content addresses.txt
Get-Content addresses.txt | Test-NetConnection -WarningAction SilentlyContinue |
Where PingSucceeded
ComputerName : yahoo.com
RemoteAddress : 74.6.231.20
InterfaceAlias : Wi-Fi
SourceAddress : 192.168.1.114
PingSucceeded : True
PingReplyDetails (RTT) : 61 ms

Powershell, combine output of a foreach loop with multiple commands

I need to get a list of properties for multiple server, but I'm stuck with the output of second command in my loop:
$(foreach ( $Net in $Nets ) {
Get-NetAdapterBinding -ComponentID ms_msclient,ms_server,ms_tcpip6 -ErrorAction SilentlyContinue | select Name,DisplayName,Enabled
Get-NetAdapterAdvancedProperty $Net -DisplayName "Speed & Duplex" | select DisplayValue
}) | Format-List
The output of first cmd is correct:
Name : LAN_Clients
DisplayName : Internet Protocol Version 6 (TCP/IPV6)
Enabled : False
Name : LAN_Clients
DisplayName : File and Print Sharing
Enabled : False
Name : LAN_Clients
DisplayName : Client for Microsoft Networks
Enabled : False
The second cmd seems ignored...
If I run cmd manually the output is correct:
Get-NetAdapterAdvancedProperty "LAN_Clients" -DisplayName "Speed & Duplex" | select DisplayValue
DisplayValue
------------
Auto Negotiation
What am I doing wrong?
You need to combine both outputs into a single object.
Try
$(foreach ( $Net in $Nets ) {
$speed = (Get-NetAdapterAdvancedProperty $Net -DisplayName "Speed & Duplex").DisplayValue
Get-NetAdapterBinding -ComponentID ms_msclient,ms_server,ms_tcpip6 -ErrorAction SilentlyContinue |
Select-Object Name,DisplayName,Enabled,
#{Name = 'Speed & Duplex'; Expression = {$speed}}
}) | Format-List
You don't need to call Get-NetAdapter, as Get-NetAdapterBinding already returns all the bindings for all the adapters.
In the foreach loop, you're not using the -Name parameter with Get-NetAdapterBinding so it's returning all the bindings for all your adapters every iteration of the loop.
You can use an expression block in Select-Object to get the additional duplex property you're after, like this:
Get-NetAdapterBinding -ComponentID ms_msclient,ms_server,ms_tcpip6 -ErrorAction SilentlyContinue |
Select-Object Name,DisplayName,Enabled, #{Name = 'Speed & Duplex'; Expression={Get-NetAdapterAdvancedProperty -InterfaceAlias $_.InterfaceAlias -DisplayName 'Speed & Duplex' | select -ExpandProperty DisplayValue }} |
Format-List
For troubleshooting purposes, try this:
$Nets = Get-NetAdapterBinding -ComponentID ms_msclient,ms_server,ms_tcpip6 -ErrorAction SilentlyContinue
foreach ($Net in $Nets.name ) {
Get-NetAdapterAdvancedProperty $Net -DisplayName "Speed & Duplex" | select DisplayValue
}

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"

PC Inventory 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

Start-Job output in CSV format

How to get the jobs output in an CSV format. When I execute the command below, I get the output on the screen, but when I export it to CSV it does not have the same format.
$wmidiskblock = {
Get-WmiObject -ComputerName $args[0] -Class Win32_LogicalDisk -Filter "DeviceID='C:'" |
Select-Object Size, Freespace
(Test-Connection -ComputerName $args[0] | Select-Object -ExpandProperty IPV4Address) |
Select-Object IPAddressToString -Unique
Get-Service -ComputerName $args[0] | ? {
($_.DisplayName -match "VMWARE") -and
($_.Name -notmatch "mbcs") -and
($_.Name -notmatch "vmvss") -and
($_.Name -notmatch "vmware-autodeploy-waiter") -and
($_.Name -notmatch "vmware-network-coredump") -and
($_.Name -notmatch "VMWareNetworkCoredumpWebserve") -and
($_.Name -notmatch "vsan-health")
} -ErrorAction Stop
}
$com = #()
$com = "Server-x" , "Server-y"
$pop = #()
foreach ($ser in $com) {
[array]$pop += Start-Job -ArgumentList $ser -ScriptBlock $wmidiskblock -Name top1
}
Get-Job -Name top1 | Receive-Job -Keep
Actual output:
Size : 64422408192
Freespace : 4908081152
RunspaceId : cdb3xxxxx-xxxx-xxxx-xxxx-xxxxxxxxx
IPAddressToString : x.x.x.x
RunspaceId : cdb3xxxxx-xxxx-xxxx-xxxx-xxxxxxxxx
Status : Running
Name : client_service
DisplayName : VMware Horizon Client
Status : Running
Name : ftnlsv3hv
DisplayName : VMware Netlink Supervisor Service
Status : Running
Name : ftscanmgrhv
DisplayName : VMware Scanner Redirection Client
Server-x
Desired output (as a CSV file):
Server Totalspace in GB Freespace in GB IP VMware ESX Agent Manager VMware Inventory Service
Server-x 100 36 144.215.150.67 Running Running
You need to transform your data to something that's actually exportable to CSV. Basically that means you need to take the bits of information you extract from the servers and put it into one object for each server:
$wmidiskblock = {
$disk = Get-WmiObject ...
$addr = (Test-Connection ...
$svc = Get-Service ...
$prop = [ordered]#{
Server = $args[0]
Totalspace = $disk.Size
Freespace = $disk.Freespace
IP = $addr
}
$svc | ForEach-Object { $prop[$_.Name] = $_.Status }
New-Object -Type PSObject -Property $prop
}
Then you can export the data received from the jobs like this:
... | Receive-Job | Export-Csv 'C:\path\to\output.csv' -NoType -Append