How to sum only 2nd column values using powershell? - powershell

sharesize.ps1
echo " "
$date1 = Get-Date
Write-Host -foreground Yellow -background Black "Script Started at $date1"
$path = "\*"
get-childitem $path | where {$_.PSIsContainer} | foreach {
$size = (Get-ChildItem $_ -recurse | where {!$_.PSIsContainer} | Measure-Object -Sum Length).Sum
$size = "{0:N2}" -f ($size / 1MB) + " MB"
$obj = new-object psobject
add-member -inp $obj noteproperty Path $_.fullName
add-member -inp $obj noteproperty "Size(MB)" $size
[array]$report += $obj
}
#display the table
$a = "<style>"
$a = $a + "BODY{background-color:green;}"
$a = $a + "TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}"
$a = $a + "TH{border-width: 2px;padding: 0px;border-style: solid;border-color: black;background-color:Yellow; font-family: Arial; font-size: 12pt}"
$a = $a + "TD{border-width: 2px;padding: 2px 6px 2px 3px;border-style: solid;border-color: black;background-color:Azure; font-family: Arial; font-size: 10pt}"
$a = $a + "</style>"
$report | Sort 'Size' -Descending | ConvertTo-HTML -head $a -title "Process Information" -body "<H2>Service Information</H2>"| Out-File -Append c:\temp\folder.html
$date2 = Get-Date
echo " "
Write-Host -foreground Yellow -background Black "Script Ended at $date2"
echo " "
Above code is working great to me, help is much appreciated for the below help.
Here my requirement is to add sum of 2nd column volues and append the output to the last line of the above code output html(c:\temp\folder.html) as,
Path | Size(MB)
C:\NVIDIA\Displaydriver | 400 MB
* | 860 MB
* | 100 MB
* | * MB
* | * MB
Total | 1000 MB(sum of all numbers in 2nd column values)
and also i need to align the 2nd column values and Total row to CENTER.
Please Help

To sum the sizes do this:
$totalSize = ($report | Measure-Object 'Size(MB)' -Sum).Sum

$total = 0
$report | % {[float]$tmp = $_."Size(MB)".TrimEnd(" MB"); $total += $tmp}
Then you can just add the $total object to your custom $report object before you convertTo-html and bango. Thanks for the neat script.
Only thing that confused me a little was your () your size property of $report makes PS think its a method, thus the quotes. Is not the best convention, but it works.
More explicitly :
...
[array]$report += $obj
}
$total = 0
$report | % {[float]$tmp = $_."Size(MB)".TrimEnd(" MB"); $total += $tmp}
$obj = new-object psobject
add-member -inp $obj noteproperty Path "Total Size: "
add-member -inp $obj noteproperty "Size(MB)" $total
[array]$report += $obj
#display the table
...
Also, Remove | Sort Size -Descending for the total to appear on the bottom.

I had a similar need and here is my simple solution:
$stuff=get-stuff
$results=
foreach ($item in $stuff) {
$item | select column1,#{N="Column 2";E={$_.column2}},description,created,#{N="Size (GB)";E={"{0:N2}" -f $_.sizegb}}
}
$results_sorted=#($results | sort created)
$results_sorted+=$item | select #{N="column1";E={"Totals"}},#{N="Column 2";E={$null}},#{N="Description";E={$null}},#{N="Created";E={$null}},#{N="Size (GB)";E={($results | Measure-Object "size (gb)" -Sum).Sum}}
$results_sorted | ft column1,"Column 2",Description,Created,"Size (GB)"

Related

Compare-Object Not Comparing Each Element of Array

I am attempting to use Compare-Object to find elements that are in one array ($fileArray) but not in another ($dictionaryArray). For some reason, Compare-Object is only comparing the last two elements in fileArray. Here is the code I am trying to run.
$dictionary = Get-Content "C:\Users\Joe\Documents\PowerShell Scripts\Work\PCI Numbers\dictionary.txt"
$file = Get-Content "C:\Users\Joe\Documents\PowerShell Scripts\Work\PCI Numbers\file.txt"
$dictionaryArray = #()
$fileArray = #()
$dictionaryLength = $dictionary | Measure-Object -Line
$fileLength = $file | Measure-Object -Line
$i = 0
while($i -lt $dictionaryLength.Lines){
$name = $dictionary | Select -Index $i
$i++
while($dictionary[$i] -ne " " -and $i -lt $dictionaryLength.Lines){
$dictionaryObject = New-Object -TypeName PSObject
$dictionaryObject | Add-Member -Name 'PC' -MemberType Noteproperty -Value $name
$dictionaryObject | Add-Member -Name 'File' -MemberType Noteproperty -Value $dictionary[$i]
$dictionaryArray += $dictionaryObject
$i++
}
$i++
}
$i = 0
while($i -lt $fileLength.Lines){
$name = $file | Select -Index $i
$i++
while($file[$i] -ne " " -and $i -lt $fileLength.Lines){
$fileObject = New-Object -TypeName PSObject
$fileObject | Add-Member -Name 'PC' -MemberType Noteproperty -Value $name
$fileObject | Add-Member -Name 'File' -MemberType Noteproperty -Value $file[$i]
$fileArray += $fileObject
$i++
}
$i++
}
$i = 0
Compare-Object -ReferenceObject $fileArray -DifferenceObject $dictionaryArray |
Where-Object {$_.SideIndicator -eq '<='} |
ForEach-Object {Write-Output $_.InputObject}
When I simply run Compare-Object -ReferenceObject $fileArray
-DifferenceObject $dictionaryArray, I get the output
InputObject SideIndicator
#{PC=Joe; File=nopethere} <=
#{PC=Joe; File=hi!!!#} <=
There are more items than this in the fileArray. When I run $fileArray, I get
PC File
Eric I like to
Eric there
Joe code because
Joe hello
Joe but why?
Joe *no\thank/ you :c
Joe nopethere
Joe hi!!!#
Why is my code not comparing each one of these objects?
EDIT
Here is dictionary.txt
Eric
because
hello there
Joe
but why?
*no\thank/ you :c
nope
Here is file.txt
Eric
I like to
there
Joe
code because
hello
but why?
*no\thank/ you :c
nopethere
hi!!!#
I use my loop to create objects. The first line of each paragraph is the "PC" for each subsequent object. Then, each line is the "File" of each object. I want to check which objects are in fileArray and not in dictionaryArray. I would expect the output to be
PC File
Eric I like to
Joe code because
Joe hello
Joe nopethere
Joe hi!!!#
Any help would be appreciated!

Loop through line for multiple values

Word Doc content: [(7)]/[(8)] [ Security Agent 1] as security trustee for the Secured Parties (the "Security Agent") ; and
Value to extract is "Security Agent 1"
It extracts 7 as thats the first within bracket.
Below code works fine, but will give only first occurence/value within brackets. Need to loop it through multiple values within bracket and give me the 3rd value in bracket
$FinalTable = Get-Content $SourceFile|
select-string -pattern $SearchKeyword |
Select -Property #{Name = 'Name'; Expression = {$_.Line}}, #{Name = 'LineNo'; Expression = {$_.LineNumber}}, #{Name='Criteria';Expression = {$_.Category}} |
ForEach-Object {
$str = $_.Name
$LineNumber = $_.LineNo
$Criteria = $_.Criteria
$start = $str.indexOf("[") + 1
$end = $str.indexOf("]", $start)
$length = $end - $start
$result = ($str.substring($start, $length)).trim()
#Creating a custom object to display in table format
$Obj = New-Object -TypeName PSCustomObject
Add-Member -InputObject $Obj -MemberType NoteProperty -Name Category -Value $Category
Add-Member -InputObject $Obj -MemberType NoteProperty -Name Description -Value $result
$obj
}
$FinalTable | Export-Csv -Path $DestinationFile -NoTypeInformation -Encoding ASCII
Trying this as theo suggested but didn't worked
$FinalTable = Get-Content $SourceFile|
select-string -pattern $SearchKeyword |
Select -Property #{Name = 'Name'; Expression = {$_.Line}}, #{Name = 'LineNo'; Expression = {$_.LineNumber}}, #{Name='Criteria';Expression = {$_.Category}} |
ForEach-Object {
$str = $_.Name
$LineNumber = $_.LineNo
$Criteria = $_.Criteria
#$start = $str.indexOf("[") + 1
#$end = $str.indexOf("]", $start)
#$length = $end - $start
#$result = ($str.substring($start, $length)).trim()
#Write-host $str
if ($str -match '(\[[^\]]+])\/(\[[^\]]+])\s*\[\s*([^\]]+)]') {
# $matches[1] --> "(7)"
# $matches[2] --> "(8)"
$result = $matches[3] # --> "Security Agent 1"
}
Write-Host $result
#Creating a custom object to display in table format
$Obj = New-Object -TypeName PSCustomObject
Add-Member -InputObject $Obj -MemberType NoteProperty -Name Category -Value $Category
Add-Member -InputObject $Obj -MemberType NoteProperty -Name Description -Value $result
$obj
}
$FinalTable | Export-Csv -Path $DestinationFile -NoTypeInformation -Encoding ASCII
You could use Regular Expression to get the parts between the brackets in a string like [(7)]/[(8)] [ Security Agent 1] as security trustee for the Secured Parties (the "Security Agent").
Instead of
$start = $str.indexOf("[") + 1
$end = $str.indexOf("]", $start)
$length = $end - $start
$result = ($str.substring($start, $length)).trim()
do
if ($str -match '\[([^\]]+)\]\/\[([^\]]+)\]\s*\[\s*([^\]]+)]') {
# $matches[1] --> "(7)"
# $matches[2] --> "(8)"
$result = $matches[3] # --> "Security Agent 1"
}
else {
$result = '' # should not happen..
}

How to concatenate a value to Select-Object's output

I have a script which finds snapshots that are older than 3 days and below are my code and output. However I want to add a new column for each VM displaying the actual age of that snapshots, say for example 5 days or 4 days. I have tried getting age by subtracting created date from today's date. But I am not sure how to add it as a column to my output.
I used this to calculate age:
$StartDate = Get-Date
$created = Get-VM |
Get-Snapshot |
Where {$_.Created -lt (Get-Date).AddDays(-1)} |
Select-Object Created
$age = New-Timespan -Start $StartDate -End $created
Full code:
Add-PSSnapin VMware.VimAutomation.Core
# HTML formatting
$a = "<style>"
$a = $a + "BODY{background-color:white;}"
$a = $a + "TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}"
$a = $a + "TH{border-width: 1px;padding: 5px;border-style: solid;border-color: black;foreground-color: black;background-color: LightBlue}"
$a = $a + "TD{border-width: 1px;padding: 5px;border-style: solid;border-color: black;foreground-color: black;background-color: white}"
$a = $a + "</style>"
Connect-VIServer -Server ***** -User ****** -Password ******
# Main section of check
Write-Host "Checking VMs for for snapshots"
$date = Get-Date
$datefile = Get-Date -UFormat '%m-%d-%Y-%H%M%S'
$filename = "C:\Temp\snaps_older_than_3\" + $datefile + ".htm"
$created = Get-VM |
Get-Snapshot |
Where {$_.Created -lt (Get-Date).AddDays(-1)} |
Select-Object Created
$age = New-Timespan -Start $StartDate -End $created
$ss = Get-VM |
Get-Snapshot |
Where {$_.Created -lt (Get-Date).AddDays(-1)} |
Select-Object vm, name, SizeGB, SizeMB, Created, powerstate + $age |
ConvertTo-HTML -Head $a -Body "<H2>VM Snapshot Report </H2>"|
Out-File $filename
Write-Host " Complete " -ForegroundColor Green
Write-Host "Your snapshot report has been saved to:" $filename
$SMTPServer = "*******"
$SMTPPort = 25
$username = "vcenter#mmmm.com"
#Define the receiver of the report
$to = "mmmmm#hcl.com"
$subject = "VM Snapshot Report"
$body = "VM Snapshot Report"
$attachment = New-Object Net.Mail.Attachment($filename)
$message = New-Object System.Net.Mail.MailMessage
$message.Subject = $subject
$message.Body = $body
$message.To.Add($to)
$message.From = $username
$message.Attachments.Add($attachment)
$smtp = New-Object System.Net.Mail.SmtpClient($SMTPServer, $SMTPPort);
$smtp.EnableSSL = $false
$smtp.Send($message)
Write-Host "Mail Sent"
Output:
I want to add a new column named "age".
Use a calculated property:
Get-VM |Select-Object VM,Name,SizeGB,SizeMB,Created,PowerState,#{Name='Age';Expression={New-TimeSpan -Start $StartDate -End $_.Created}}
From the help text for Select-Object:
-Property
Specifies the properties to select. Wildcards are permitted.
The value of the Property parameter can be a new calculated property.
To create a calculated property, use a hash table. Valid keys are:
Name (or Label) <string>
Expression <string> or <script block>

Sum Columns Using Powershell

I have written the following PowerShell script for getting disk space information for servers in our environment.
$servers = Get-Content E:\POC.txt
$array = #()
foreach($server in $servers){
$sysinfo = Get-WmiObject Win32_Volume -ComputerName $server
for($i = 0;$i -lt $sysinfo.Count; $i++){
$sname = $sysinfo[$i].SystemName
$servername = $server
$label = $sysinfo[$i].Label
if(($label) -and (!($label.Contains("FILLER")))){
write-host "Processing $label from $server"
$name = $sysinfo[$i].Name
$capacity = [math]::round(($sysinfo[$i].Capacity/1GB),2)
$fspace = [math]::round(($sysinfo[$i].FreeSpace/1GB),2)
$sused = [math]::round((($sysinfo[$i].Capacity - $sysinfo[$i].FreeSpace)/1GB),2)
$fspacepercent = [math]::Round((($sysinfo[$i].FreeSpace*100)/$sysinfo[$i].Capacity),2)
$obj = New-Object PSObject
$obj | Add-Member -MemberType NoteProperty -Name "SystemName" -Value $sname
$obj | Add-Member -MemberType NoteProperty -Name "ServerName" -Value $server
$obj | Add-Member -MemberType NoteProperty -Name "Label" -Value $label
$obj | Add-Member -MemberType NoteProperty -Name "Name" -Value $name
$obj | Add-Member -MemberType NoteProperty -Name "Capacity(GB)" -Value $capacity
$obj | Add-Member -MemberType NoteProperty -Name "FreeSpace(GB)" -Value $fspace
$obj | Add-Member -MemberType NoteProperty -Name "Used(GB)" -Value $sused
$obj | Add-Member -MemberType NoteProperty -Name "FreeSpace%" -Value $fspacepercent
$array += $obj
}
}
$array += write-output " "
$totalSize = ($array | Measure-Object 'Capacity(GB)' -Sum).Sum
$array += $totalsize
$array += write-output " "
}
$filename = "E:\VolumeReport.csv"
$array | Export-CSV $filename -NoTypeInformation
One additional requirement here is to get the sum of the columns for Capacity, Size and Freespace for each server. I tried using Measure-Object but no success.
No values are getting outputted here. Just blank. Please look into this and kindly assist.
Let try this on for size shall we.
$servers = Get-Content E:\POC.txt
$propertyOrdered = "SystemName","ServerName","Label","Name","Capacity(GB)","FreeSpace(GB)","Used(GB)","FreeSpace%"
$filename = "C:\temp\VolumeReport.csv"
('"{0}"' -f ($propertyOrdered -join '","')) | Set-Content $filename
foreach($server in $servers){
$sysinfo = Get-WmiObject Win32_Volume -ComputerName $server
$serverDetails = #()
for($i = 0;$i -lt $sysinfo.Count; $i++){
$sname = $sysinfo[$i].SystemName
$servername = $server
$label = $sysinfo[$i].Label
if(($label) -and (!($label.Contains("FILLER")))){
write-host "Processing $label from $server"
$name = $sysinfo[$i].Name
$capacity = [math]::round(($sysinfo[$i].Capacity/1GB),2)
$fspace = [math]::round(($sysinfo[$i].FreeSpace/1GB),2)
$sused = [math]::round((($sysinfo[$i].Capacity - $sysinfo[$i].FreeSpace)/1GB),2)
$fspacepercent = [math]::Round((($sysinfo[$i].FreeSpace*100)/$sysinfo[$i].Capacity),2)
$props = #{
"SystemName" = $sname
"ServerName" = $server
"Label" = $label
"Name" = $name
"Capacity(GB)" = $capacity
"FreeSpace(GB)" = $fspace
"Used(GB)" = $sused
"FreeSpace%" = $fspacepercent
}
# Build this server object.
$serverDetails += New-Object PSObject -Property $props
}
}
# Output current details to file.
$serverDetails | Select $propertyOrdered | ConvertTo-Csv -NoTypeInformation | Select-Object -Skip 1 | Add-Content $filename
#Calculate Totals and append to file.
$totals = '"","","","Totals",{0},{1},{2},""' -f ($serverDetails | Measure-Object -Property "Capacity(GB)" -Sum).Sum,
($serverDetails | Measure-Object -Property "FreeSpace(GB)" -Sum).Sum,
($serverDetails | Measure-Object -Property "Used(GB)" -Sum).Sum
$totals | Add-Content $filename
}
Part of the issue here is that you were mixing object output and static string output which most likely would have been holding you back. I tidied up the object generation in a way that should be 2.0 compliant. Not that what you were going was wrong in anyway but this is a little more pleasing to the eye then all the Add-Members
I removed $array since it did not have a place anymore since the logic here is constantly output data to the output file as supposed to storing it temporarily.
For every $server we build an array of disk information in the variable $serverDetails. Once all the disks have been calculated (using your formulas still) we then create a totals line. You were not really clear on how you wanted your output so I guessed. The above code should net output like the following. (It looks a lot nicer in Excel or in a csv aware reader. )
"SystemName","ServerName","Label","Name","Capacity(GB)","FreeSpace(GB)","Used(GB)","FreeSpace%"
"server01","server01","System Reserved","\\?\Volume{24dbe945-3ea6-11e0-afbd-806e6f6e6963}\","0.1","0.07","0.03","71.85"
"","","","Totals",0.1,0.07,0.03,""
"server02","server02","System Reserved","\\?\Volume{24dbe945-3ea6-11e0-afbd-806e6f6e6963}\","0.1","0.07","0.03","69.27"
"server02","server02","images","I:\","1953.12","152.1","1801.02","7.79"
"server02","server02","Data","E:\","79.76","34.59","45.18","43.36"
"","","","Totals",2032.98,186.76,1846.23,""

PowerShell outtput to HTML

Using the following and would like to know how to output the results to HTML file
$Start = (Get-Date).AddMinutes(-5)
$Computername = gc C:\Temp\List.txt
$Events = gc C:\Temp\ErrorCodes.txt
Get-EventLog -AsString -ComputerName $Computername |
ForEach-Object {
# write status info
Write-Progress -Activity "Checking Eventlogs on \\$ComputerName" -Status $_
# get event entries and add the name of the log this came from
Get-EventLog -LogName $_ -EntryType Error, Warning -After $Start -ComputerName $ComputerName -ErrorAction SilentlyContinue |
Add-Member NoteProperty EventLog $_ -PassThru | Where-Object {$Events -contains $_.eventid}
} |
# select the properties for the report
Select-Object EventLog, EventID, TimeGenerated, EntryType, Source, Message
This will get it to print with pretty colors. You can tinker around with it and change whatever you want.
$a = "<style>"
$a = $a + "BODY{background-color:peachpuff;}"
$a = $a + "TABLE{border-width: 1px;border-style: solid;border-color:black;border-collapse: collapse;}"
$a = $a + "TH{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:thistle}"
$a = $a + "TD{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:palegoldenrod}"
$a = $a + "</style>"
$Variable = get-what_I_want
$Variable2 = get-what_I_want
$VariableHTML = $Variable | ConvertTo-HTML -head $a -body "<H2>Title I want</H2>"
$Variable2HTML = $Variable2 | ConvertTo-HTML -head $a -body "<H1>Header One</H1> <H2>Header Two</H2> <H3>Header Three</H3> <p>Paragraph<p/>"
$VariableHTML > C:\PoSH\My_Exported_HTML.html
I added a second variable. As you can see, you can add different levels of headers and a Paragraph. I found this helpful for single line items or if you want a better description.
If I would say: ConvertTo-Html is what you need, than probably that would be enough to add a comment.
Instead I will say: before asking questions outside PowerShell, ask them inside PowerShell first.
Get-Help *html*