Create Table with Variables in PowerShell

2019-05-08 22:39发布

问题:

I'm still learning my way around PowerShell scripting and I'm working on a script to calculate the free space percentage of my file servers and send an e-mail notification when a drive reaches 10% of free space remaining or less (this happens roughly once a month, and I need to know before I get e-mailed from client's that there's no more space). As of now the script works great and is set up to run every morning via Windows Task. But the current formatting that I have in place for the output is done manually. I was wondering if there was a way to pass the variables from the information that was gathered and calculated with the Get-WmiObject function. I've tried the Format-Table and attempted messing with hash tables, but to no avail. Any ideas would be helpful. Thanks.

# Set Parameters
$file = "c:\location\Lowdisk.txt"
Clear-Content $file

$emailTO = "Someone@SomeDomain.com"
$emailFrom = "Someone@SomeDomain.com"
$smtpServer = "smtpServer"

$diskspace = "3"
$computers = ("FSCN01","FSCN02","FSCN03","FSCN04")
echo "Server Name       Drive       Drive Size       Free Space       % Free" >> $file
$i = 0

# Get Drive Data
foreach($computer in $computers)
{
$drives = Get-WmiObject -ComputerName $computer Win32_LogicalDisk | Where-Object {$_.DriveType -eq 3}
foreach($drive in $drives)
{
    $ID = $drive.DeviceID
    $size1 = $drive.size / 1GB
    $size = "{0:N1}" -f $size1
    $free1 = $drive.freespace / 1GB
    $free = "{0:N1}" -f $free1
    $a = $free1 / $size1 * 100
    $b = "{0:N1}" -f $a
        # Monitor for drive free space % under 10%
        if ($b -lt 10)
        {
            echo "$computer         $ID          $size         $free         $b" >> $file
            $i++
        }
}
}
# Send notification if script finds more than 0 drives with less than 35% free space 
    if ($i -gt 0) 
   { 
       foreach ($user in $emailTo) 
            { 
        echo "Sending Email Notification to $user" 
        $smtp = New-Object Net.Mail.SmtpClient($smtpServer) 
        $subject = "Server with Low Disk Space" 
        foreach ($line in Get-Content $file) 
                { 
                $body += "$line `n" 
                } 
        Send-MailMessage -to $user -From $emailFrom -Attachments $file -SmtpServer $smtpServer -Subject $Subject -Body $body 
        $body = "" 
                } 
   } 

回答1:

Format-Table works best when you have all the data of interest in a single type of object. I would recommend creating custom objects for this e.g.:

foreach($computer in $computers)
{
    $drives = Get-WmiObject -ComputerName $computer Win32_LogicalDisk | Where-Object {$_.DriveType -eq 3}
    foreach($drive in $drives)
    {
        $obj = new-object psobject -Property @{
                   ComputerName = $computer
                   Drive = $drive.DeviceID
                   Size  = $drive.size / 1GB
                   Free  = $drive.freespace / 1GB
                   PercentFree = $drive.freespace / $drive.size * 100
               }
        if ($obj.PercentFree -lt 10) {
            $obj | Format-Table ComputerName,Drive,Size,Free,PercentFree
            $i++
        }
    }
}

If you want to change the display format then in the format-table command you can do this:

$obj | Format-Table ComputerName,Drive,@{n='Size';e={'{0:N1}' -f $_.Size}},Free,PercentFree


回答2:

Keith has it covered, but as my reply was half written anyway, here it is. My version needs no new objects to be created and has the filtering as part of the pipeline.

As Keith says, keep everything as an object until the last minute. If you need to force PowerShell to format, use 'out-string'.

Also, look out for support for lists. Many commands will take a list as a parameter (e.g. list of computer names, email recipients) without the need for for-each loops. This can make code more concise, but arguably less readable, especially for a beginner. Anyway, here's what I cooked up:

$comps=@("server1","server2","server3","server4")
$smtpServer = "mail.mydomain.com"
$toList = @("someone@mydomain.com","anotherperson@mydomain.com")
$minPercent = 10

$tableSpec = @(
        @{label="Computer";expression={$_.SystemName}},
        @{label="Disk";expression={$_.DeviceID}},
        @{label="Size Gb";expression={[int]($_.size / 1Gb)}},
        @{label="PercentFree";expression={[int]($_.FreeSpace / $_.Size * 100)}}
    )

$report = (

    Get-WmiObject -ComputerName $comps -Class Win32_LogicalDisk |
    Where-Object { ($_.DriveType -eq 3) -and ($_.FreeSpace -lt ($_.Size * $minPercent / 100)) } |
    Sort-Object SystemName, DeviceID |
    ft -property $tableSpec -AutoSize |
    Out-String

    )

Send-MailMessage -Body $report -To $toList -Subject "Disk space report" -SmtpServer $smtpServer