Send slack message with result from Powershell - powershell

I am trying to send slack message by powershell and I got stuck. here is my script. Looks like I can't use $result for -text.
What I am trying to do is to send an alert to slack channel if there is any free disk space lower than 15% or 10%.
I am using PSSlack from Powershell Gallery.
$ErrorActionPreference = "Continue";
$percentCritcal = 15;
$computers = Get-Content "D:\Disk_Usage\ServerList.txt"
$result = foreach($computer in $computers)
{
$disks = Get-WmiObject -ComputerName $computer -Class Win32_LogicalDisk -Filter "DriveType = 3"
$computer = $computer.ToUpper()
foreach($disk in $disks)
{
$Size = $disk.Size
$Freespace = $disk.FreeSpace
$sizeGB = [Math]::Round($Size / 1073741824, 2)
$freeSpaceGB = [Math]::Round($Freespace / 1073741824, 2)
$percentFree = [Math]::Round(($freespace / $size) * 100, 2);
$ResultHash = [ordered]#{
Computer = $computer
Drive = $disk.DeviceID
SizeGB = $sizeGB
UsedGB = $sizeGB - $freeSpaceGB
FreeGB = $freeSpaceGB
PercFree = $percentFree
}
New-Object -TypeName PSObject -Property $ResultHash
}
}
$Result = $Result | Where-Object {$_.PercFree -lt 10}
if ($Result)
{
$token = 'xxxxxxxxxxx'
$Result = $Result | Format-Table | Out-String
New-SlackMessageAttachment -Color $_PSSlackColorMap.red `
-Title 'Disk Free Space Alert' `
-Text $result `
-Fallback 'Bad boy' |
New-SlackMessage -Channel '#it-test' `
-IconEmoji :bomo: `
-AsUser `
-Username 'BOT' |
Send-SlackMessage -Token $token
}
The result is like this, it is repeating the same drive for couple times
Any idea?

The problem with your code is that $Result never gets populated with anything. The simplest fix would be to create an object in the ForEach loop, which will then populate $Result.
For example:
$result = foreach($computer in $computers)
{
$disks = Get-WmiObject -ComputerName $computer -Class Win32_LogicalDisk -Filter "DriveType = 3"
$computer = $computer.ToUpper()
foreach($disk in $disks)
{
$Size = $disk.Size
$Freespace = $disk.FreeSpace
$sizeGB = [Math]::Round($Size / 1073741824, 2)
$freeSpaceGB = [Math]::Round($Freespace / 1073741824, 2)
$ResultHash = [ordered]#{
Computer = $computer
deviceID = $disk.DeviceID
volName = $disk.VolumeName
percentFree = [Math]::Round(($Freespace / $Size) * 100, 2)
sizeGB = $sizeGB
freeSpaceGB = $freeSpaceGB
usedSpaceGB = $sizeGB - $freeSpaceGB
}
New-Object -TypeName PSObject -Property $ResultHash
}
}
Explanation:
The above code has taken your existing variables and turned them in to properties of a hash table #{ }. This hash table is then used to create the properties of an object with New-Object.
Because New-Object is on a line on it's own, it's result goes in to the pipeline, which is ultimately output to $Result because that's where you send the result of the ForEach.
[ordered] in front of the Hashtable should keep the properties in the order that they've been defined. Note that this requires PowerShell v3 or above.
Depending on how you want it to look, you might want to also do this to $Result after the ForEach and before you use it in the Slack Message:
$Result = '```' + ($Result | Format-Table | Out-String) + '```'
This should make the message formatted as fixed width code in a tabular format. Of course you might want to modify the output differently, just a suggestion.

Related

I want to get details of task manger users tab about ram and cpu utilization

I have following script, i want to get each users details of ram and cpu utilization separately in csv file. but from this script i am getting all users details in a single line instead of individually user based resources utilization details in csv file.
This is my Powershell code
GC c:\List.txt | % {
$xl = New-Object -ComObject "Excel.Application"
$xl.Visible = $true
$xl.DisplayAlerts = $false #for debugging, no prompts to save, etc.
$ConvertToGB = (1024 * 1024 * 1024)
$wkbk = $xl.Workbooks.Add()
$sheet = $wkbk.WorkSheets.Item(1)
$sheet.Name = "Transposed"
$Comp = $_
If (Test-Connection $Comp -Quiet) {
$Luser = (Get-WmiObject -class win32_process -Filter "Name='Explorer.exe'" -ComputerName $Comp |
% {$_.GetOwner().User} | Sort-Object -Unique) -join ","
$Mem = GWMI -Class win32_operatingsystem -computername $COMP
New-Object PSObject -Property #{
Server = $Comp
"CPU_Usage" = "$((GWMI -ComputerName $COMP win32_processor | Measure-Object -property LoadPercentage -Average).Average)"
"Memory_Usage" = "$("{0:N2}" -f ((($Mem.TotalVisibleMemorySize - $Mem.FreePhysicalMemory)*100)/ $Mem.TotalVisibleMemorySize)) %"
"DiskSpace" = "$("{0:N2}" -f (Get-WmiObject -Class win32_logicaldisk -ComputerName $COMP -Filter "DriveType = 3"| Select-Object "Size","FreeSpace"))"
#$Comp = ($disk.Size / $ConvertToGB),($disk.FreeSpace / $ConvertToGB)
"logged_Users" = $Luser
}
}
Else {
}
$results = Get-Service -Name *bits*| Select Server #,"CPU usage","Memory usage","DiskFreeSpace","logged Users"
$column = 1
$row = 1
foreach ($psRow in $results) {
foreach ($item in $psRow.PSObject.Properties) {
$sheet.Cells.Item($row, $column) = $item.Name
$column++
#$sheet.Cells.Item($row, $column) = $item."CPU","Memory_Usage","DiskSpace","logged_Users"
$row++
$column--
}
} }
$obj =New-Object PSObject -Property #{
Server = $Comp
"CPU_Usage" = "$((GWMI -ComputerName $COMP win32_processor | Measure-Object -property LoadPercentage -Average).Average)"
"Memory_Usage" = "$("{0:N2}" -f ((($Mem.TotalVisibleMemorySize - $Mem.FreePhysicalMemory)*100)/ $Mem.TotalVisibleMemorySize)) %"
"DiskSpace" = Get-WmiObject -Class win32_logicaldisk -ComputerName $COMP -Filter "DriveType = 3"| Select-Object "Size","FreeSpace"
#$Comp = ($disk.Size / $ConvertToGB),($disk.FreeSpace / $ConvertToGB)
"logged_Users" = $Luser
}
Write-Output "DiskSpace, $($obj.DiskSpace.Size), $($obj.DiskSpace.FreeSpace)"
Write-Output "Server, $($obj.Server)"
Write-Output "Memory_Usage, $($obj.Memory_Usage)"
Write-Output "logged_Users, $($obj.logged_Users)"
Write-Output "CPU_Usage, $($obj.CPU_Usage)"
$obj | ConvertTo-Csv
These are the results i am getting
Memory_Usage : 91.90 %
CPU_Usage : 99
Server : 127.0.0.1
logged_Users : user1,user2,user3,userA
DiskSpace : {#{Size=718642417664; FreeSpace=317923561472}, #{Size=214747312128; FreeSpace=182724562944}, #{Size=26507997184; FreeSpace=3710320640},
#{Size=1099511627776; FreeSpace=989560467456}}
I need this type of result in csv
logged users | Memory Usage in MB | CPU Usage % |
User1 25300 8
User2 33658 15
User3 48793 7
UserA 23564 5
why don't you use select-object? I can't test it b/c your script doesn't have the full code for me to test it, but it would be a little something like:
get-psdrive | Where Free* | Select-Object Name, #{Name='UsedGB'; Expression={$_.Used/1GB}}, #{Name='FreePerc'; Expression={'{0:p0}' -f((($_.Used)/1GB) / (($_.Free + $_.Used)/1GB))}}, #{Name='TotalSize'; Expression={($_.Free + $_.Used)/1GB}}
Result:
Name UsedGB FreePerc TotalSize
---- ------ -------- ---------
A 192.771030426025 81% 238.473628997803
C 336.458614349365 36% 930.742183685303
D 7043.1279296875 95% 7452.00390625
E 110.902645111084 47% 238.473628997803
You can use this to build the table you want.
From there, to export it to csv; I would assume you can export it with a pipe follow by export-csv -path (Destination + file name) -NoTypeInformation

powershell script - TimeGenerated Last 24 hours

I have a functional PowerShell script that I'm using to capture user logons and logoffs for single local machine. The script works fine, but I'm having a difficult time trying to pull the last 24 hours from current date/time. I have $Date = [DateTime]::Now.AddDays(-1) at the top of my script, but it appears to be getting ignored.
Can anyone tell me what I'm missing?
powershell
$Date = [DateTime]::Now.AddDays(-1)
$Date.tostring("MM-dd-yyyy_HH,mm,ss")
$UserProperty = #{n="user";e={(New-Object System.Security.Principal.SecurityIdentifier $_.ReplacementStrings[1]).Translate([System.Security.Principal.NTAccount])}}
$TypeProperty = #{n="Action";e={if($_.EventID -eq 7001) {"Logon"} else {"Logoff"}}}
$TimeProperty = #{n="Time";e={TimeGenerated}}
Get-EventLog System -Source Microsoft-Windows-Winlogon | select $UserProperty,$TypeProperty,$TimeProperty | export-csv -path C:\Temp\TrackLogin.csv -NoTypeInformation
Your current code is very limited as it doesn't interact with the date at all. Here is a bit of code I use in a function. Should work if run as an admin.
$Days = 1
$Computer = $env:COMPUTERNAME
$events = #()
$events += Get-WinEvent -ComputerName $Computer -FilterHashtable #{
LogName='Security'
Id=#(4800,4801)
StartTime=(Get-Date).AddDays(-$Days)
}
$events += Get-WinEvent -ComputerName $Computer -FilterHashtable #{
LogName='System'
Id=#(7001,7002)
StartTime=(Get-Date).AddDays(-$Days)
}
$type_lu = #{
7001 = 'Logon'
7002 = 'Logoff'
4800 = 'Lock'
4801 = 'Unlock'
}
$ns = #{'ns'='http://schemas.microsoft.com/win/2004/08/events/event'}
$target_xpath = "//ns:Data[#Name='TargetUserName']"
$usersid_xpath = "//ns:Data[#Name='UserSid']"
If($events) {
$results = ForEach($event in $events) {
$xml = $event.ToXml()
Switch -Regex ($event.Id) {
'4...' {
$user = (Select-Xml -Content $xml -Namespace $ns -XPath $target_xpath).Node.'#text'
Break
}
'7...' {
$sid = (Select-Xml -Content $xml -Namespace $ns -XPath $usersid_xpath).Node.'#text'
$user = (New-Object -TypeName 'System.Security.Principal.SecurityIdentifier' -ArgumentList $sid).Translate([System.Security.Principal.NTAccount]).Value
Break
}
}
New-Object -TypeName PSObject -Property #{
Time = $event.TimeCreated
Id = $event.Id
Type = $type_lu[$event.Id]
User = $user
}
}
If($results) {
$results | sort Time -Descending
}
}

Combining results from variables into hash table and display all values

My codes below gather boot time, server specs, disks, etc and stored into multiple variables. Then, i throw them into a new object to display the results nicely. The problem with displaying disks results, i don't mind that it displays all disks in one column but it doesn't show all of the disks. Using Format-table -autosize doesn't solve the problem.
If i can't fit all values in one column, what is the right approach to display drives letter in its own assigned field, dynamically.
IE; Column1 for value of disk1, Column 2 for value of disk 2...
I've removed some codes below to reduce the amount of lines.
$BootTime = GET-WmiObject win32_Operatingsystem -ComputerName $server -EA
STOP | select #{n='ServerName';e={$_.csname}},#{n='LastBootUpTime';e={$_.ConverttoDateTime($_.lastbootuptime)}} ,#{n='LocalTime';e={$_.ConverttoDateTime($_.LocalDateTime)}}
$Disks = Get-WmiObject win32_logicaldisk -ComputerName $server -Filter Drivetype=3 |`
Select-Object #{n = "Drive Letter";e = {$_.DeviceID}},`
#{n = "Total(GB)";e = {"{0:N1}" -f( $_.Size / 1gb)}},`
#{n = "FreeSpace(GB)";e = {"{0:N1}" -f( $_.Freespace / 1gb ) }},`
#{n = "FreeSpace(%)"; e = {"{0:P0}" -f ($_.freespace/$_.size)}}
New-Object -Type PSObject -Property #{
ServerName = $BootTime.Servername
LastBootTime = $BootTime.LastBootUptime
LocalTime = $BootTime.LocalTime
UpTime = $BootTime.UpTime
OS = $BootTime.OS
Domain = $Domain.Domain
Drive = $Disks."Drive Letter"
"Disks(GB)" = $Disks."Total(GB)"
"FreeSpace(GB)" = $Disks."FreeSpace(GB)"
"FreeSpace(%)" = $Disks."FreeSpace(%)"
}
}
CATCH
{
New-Object -Type PSObject -Property #{
ServerName = $Server
LastBootTime = "Try Pinging"
LocalTime = "WMI Not Responding"
UpTime = "Possibly WMI not functioning or server is hung"#$null
OS = $null
Drive = $null
"Disks(GB)" = $null
"FreeSpace(GB)" = $null
"FreeSpace(%)" = $null
"Memory(GB)" =$null
PhysicalCPU = $null
CPUName = $null
Cores = $null
Manufacturer = $null
Model = $null
}
}
}
$Output| Select ServerName,LastBootTime, LocalTime, UpTime,Domain,OS, PhysicalCPU, CPUName, Cores, "Memory(GB)", Drive, "Disks(GB)", "FreeSpace(GB)", "FreeSpace(%)" , Manufacturer, Model
Current Results:
Drive : {C:, E:, F:, G:...}
Disks(GB) : {149.7, 500.0, 1,945.0, 1,024.0...}
FreeSpace(GB) : {90.0, 358.6, 1,411.1, 909.9...}
FreeSpace(%) : {60%, 72%, 73%, 89%...}
Desired Results:
Drive : {C:, E:, F:, G:,H:}
Disks(GB) : {149.7, 500.0, 1,945.0, 1,024.0,100}
OR
Drive1 : C:
Drive2: D:
Disk(GB) 1 :149.7
Disk(GB) 2 : 500.0
This will be my answer:
$server="localhost"
$BootTime = GET-WmiObject win32_Operatingsystem -ComputerName $server -EA STOP | select #{n='ServerName';e={$_.csname}},#{n='LastBootUpTime';e={$_.ConverttoDateTime($_.lastbootuptime)}},#{n='LocalTime';e={$_.ConverttoDateTime($_.LocalDateTime)}},Caption,OSArchitecture
$Disks = Get-WmiObject win32_logicaldisk -ComputerName $server -Filter Drivetype=3 | Select-Object #{n = "Drive Letter";e = {$_.DeviceID}},#{n = "Total(GB)";e = {"{0:N1}" -f( $_.Size / 1gb)}},#{n = "FreeSpace(GB)";e = {"{0:N1}" -f( $_.Freespace / 1gb ) }},#{n = "FreeSpace(%)"; e = {"{0:P0}" -f ($_.freespace/$_.size)}}
try{
foreach($disk in $disks){
New-Object -Type PSObject -Property #{
ServerName = $BootTime.Servername
LastBootTime = $BootTime.LastBootUptime
LocalTime = $BootTime.LocalTime
#UpTime = $BootTime.UpTime #not in code
OS = $BootTime.Caption
OSArchitecture = $BootTime.OSArchitecture
Domain = $Domain.Domain
"Letter"= $disk."Drive Letter"
"Disk(GB)" = $disk."Total(GB)"
"FreeSpace(GB)" = $disk."FreeSpace(GB)"
"FreeSpace(%)" = $disk."FreeSpace(%)"
}
}
}
CATCH{
Write-Error $_.Exception.Message
exit -1
}

powershell drives calculator

So I have the below code which works quite well but for some reason it's only calculating my D: drive and not also my C: drive?
$computerName = Get-Wmiobject Win32_ComputerSystem
$computerOS = Get-Wmiobject Win32_OperatingSystem
$computerHDD = Get-Wmiobject Win32_LogicalDisk -Filter drivetype=3
ForEach($HDD in $computerHDD){
$txtObject = New-Object PSObject -property #{
'ComputerName' = $computerName.Name
'ComputerModel' = $computerName.Model
'SerialNumber' = $computerName.SerialNumber
'HDDSize' = "{0:N2}" -f ($HDD.Size/1GB)
'HDDFree' = "{0:P2}" -f ($HDD.FreeSpace/$HDD.Size)
'OS' = $computerOS.caption
'OS_type' = $computerOS.OSArchitecture
'User' = $computerName.UserName
}
}
$txtObject | Select-Object ComputerName, ComputerModel, SerialNumber, HDDSize, HDDFree, OS, Os_type, User | Out-File "$PSSCriptRoot\computer_info.txt" -Append
seems like you would need to make an array. Try this...
$computerName = Get-Wmiobject Win32_ComputerSystem
$computerOS = Get-Wmiobject Win32_OperatingSystem
$computerHDD = Get-Wmiobject Win32_LogicalDisk -Filter drivetype=3
$output = #()
ForEach($HDD in $computerHDD){
$txtObject = New-Object PSObject -property #{
'ComputerName' = $computerName.Name
'ComputerModel' = $computerName.Model
'SerialNumber' = $computerName.SerialNumber
'HDDSize' = "{0:N2}" -f ($HDD.Size/1GB)
'HDDFree' = "{0:P2}" -f ($HDD.FreeSpace/$HDD.Size)
'OS' = $computerOS.caption
'OS_type' = $computerOS.OSArchitecture
'User' = $computerName.UserName
}
$output += $txtObject
}
$output | Select-Object ComputerName, ComputerModel, SerialNumber, HDDSize, HDDFree, OS, Os_type, User | Out-File "$PSSCriptRoot\computer_info.txt" -Append
You're overwriting $txtObject on every iteration of the loop, so your output only contains the drive from the final iteration. Instead, you should be initializing $txtObject as an array and then appending each drive's information to that:
$computerHDD = Get-Wmiobject Win32_LogicalDisk -Filter drivetype=3
$txtObject = #()
ForEach($HDD in $computerHDD){
$txtObject += New-Object PSObject -property #{
# ...
}
}
$txtObject | Select-Object ... | Out-File "$PSSCriptRoot\computer_info.txt" -Append
Better yet, you can eliminate the loop and the variable and just use the pipeline:
$computerName = Get-WmiObject Win32_ComputerSystem
$computerOS = Get-WmiObject Win32_OperatingSystem
Get-WmiObject Win32_LogicalDisk -Filter drivetype=3 `
| ForEach-Object -Process {
New-Object PSObject -Property #{
'ComputerName' = $computerName.Name
'ComputerModel' = $computerName.Model
'SerialNumber' = $computerName.SerialNumber
'HDDSize' = "{0:N2}" -f ($_.Size/1GB)
'HDDFree' = "{0:P2}" -f ($_.FreeSpace/$_.Size)
'OS' = $computerOS.caption
'OS_type' = $computerOS.OSArchitecture
'User' = $computerName.UserName
};
} | Out-File "$PSSCriptRoot\computer_info.txt" -Append
Note that New-Object above is nearly identical to your original code except $_ has to be used instead of $HDD.

PowerShell add objects to body of email

I want to be able to collect information from this script and put it in the body of an email. For the most part it seems to work except I want serialnumber, osversion, model, loggedin on different lines in the body of the email.
[CmdletBinding()]
param (
$computername = (Read-Host "Enter Computer Name"),
$subject = 'Serial Numbers',
$to = 'test#test.com',
$bcc = 'test#test.com',
$body = $Collection,
#$body = (Get-Content -path "c:\powershell\serialnumber\SerialNumber.csv"),
#$mail = "mailto:$to&subject=$subject&body=$body",
[string]$ErrorLog = 'c:\powershell\useful\errorlog\retry.txt',
[switch]$LogErrors
)
[Array]$Collection = foreach($computer in $computername)
{
$os = Get-WmiObject `
Win32_OperatingSystem -computer $computer
$bios = Get-WmiObject `
Win32_BIOS -computer $computer
$model = Get-WmiObject `
Win32_ComputerSystem -computer $computer
$Monitor = Get-WmiObject -computer $computer WmiMonitorID -Namespace root\wmi |
ForEach-Object {($_.UserFriendlyName -notmatch 0 |
foreach {[char]$_}) -join ""; ($_.SerialNumberID -notmatch 0 |
foreach {[char]$_}) -join ""}
$body = New-Object -TypeName PSObject -Property #{
Computername = $computer;
LoggedIn = $Model.username;
OSVersion = $os.Caption;
SerialNumber = $bios.SerialNumber;
Model = $Model.Model;
Monitor = $Monitor;
}
#$obj | convertTo-csv | out-string
#$obj = $body
#$Collection = [string]$body
#[String]$Collection
[string]$body
Start-Process -FilePath "mailto:$to&bcc=$bcc&subject=$subject&body=$body"
}
$Collection
You can't use an object directly as the body of an email, it must be a [string]. Try this:
$body = New-Object -TypeName PSObject -Property #{
Computername = $computer;
LoggedIn = $Model.username;
OSVersion = $os.Caption;
SerialNumber = $bios.SerialNumber;
Model = $Model.Model;
Monitor = $Monitor;
} | format-list | out-string