PowerShell add objects to body of email - powershell

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

Related

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.

get local admin users with password age

I am working on once assignment where want to get a list of local Windows admin users with X password age. Got below function for local admin users and other one for age. Please help me integrate these.
I have below command can work with users list to fetch details from specific groups and hostnames.
Get-Content -Path "D:\Groups.txt" | ForEach-Object {
Get-GroupMember -ComputerName (Get-Content -Path "D:\servers.txt") -LocalGroup $_
} | Export-Csv -Path D:\Getgroupmembers_$(Get-Date -Format ddMMyyyy).csv -NoTypeInformation
List of users:
function Get-GroupMember {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[Alias('Group')]
[string]$LocalGroup,
[Alias('CN','Computer')]
[string[]]$ComputerName = '.'
)
foreach ($Computer in $ComputerName) {
Write-Verbose "Checking membership of localgroup: '$LocalGroup' on $Computer"
try {
([adsi]"WinNT://$Computer/$LocalGroup,group").psbase.Invoke('Members') | ForEach-Object {
New-Object -TypeName PSCustomObject -Property #{
ComputerName = $Computer
LocalGroup = $LocalGroup
Member = $_.GetType().InvokeMember('Name', 'GetProperty', $null, $_, $null)
}
}
Write-Verbose "Successfully checked membership of localgroup: '$LocalGroup' on $Computer"
} catch {
Write-Warning $_
}
}
}
TO check Password age we can use below code and we need to integrate these two using one command:
function Get-PwdAge {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$false,
Position=1,
ValueFromPipeline=$false,
ValueFromPipelineByPropertyName=$false)]
[String]$Usr,
[Switch]$All
)
$filter = "(&(objectCategory=person)(objectClass=user)(name=$Usr))"
if ($All) {
$filter = '(&(objectCategory=person)(objectClass=user))'
}
$root = New-Object System.DirectoryServices.DirectoryEntry("LDAP://RootDSE")
$searcher = New-Object System.DirectoryServices.DirectorySearcher $filter
$SearchRoot = $root.defaultNamingContext
$searcher.SearchRoot = "LDAP://CN=Users,$SearchRoot"
$searcher.SearchScope = 'SubTree'
$searcher.SizeLimit = 0
$searcher.PageSize = 1000
$searcher.FindAll() | ForEach-Object {
$account = $_.GetDirectoryEntry()
$pwdset = [DateTime]::FromFileTime($_.Properties.Item("pwdLastSet")[0])
$age = (New-TimeSpan $pwdset).Days
$info = 1 | Select-Object Name, Login, AgeInDays, LastSet
$info.Name = $account.DisplayName[0]
$info.Login = $account.SamAccountName[0]
$info.AgeInDays = $age
$info.LastSet = $pwdset
$info
}
}
Param
(
[Parameter(Position=0,Mandatory=$false)]
[ValidateNotNullorEmpty()]
[Alias('cn')][String[]]$ComputerName=$Env:COMPUTERNAME,
[Parameter(Position=1,Mandatory=$false)]
[Alias('un')][String[]]$AccountName,
[Parameter(Position=2,Mandatory=$false)]
[Alias('cred')][System.Management.Automation.PsCredential]$Credential
)
$Obj = #()
$now = Get-Date
Foreach($Computer in $ComputerName)
{
If($Credential)
{
$AllLocalAccounts = Get-WmiObject -Class Win32_UserAccount -Namespace "root\cimv2" `
-Filter "LocalAccount='$True'" -ComputerName $Computer -Credential $Credential -ErrorAction Stop
}
else
{
$AllLocalAccounts = Get-WmiObject -Class Win32_UserAccount -Namespace "root\cimv2" `
-Filter "LocalAccount='$True'" -ComputerName $Computer -ErrorAction Stop
}
$Obj = $AllLocalAccounts | ForEach-Object {
$user = ([adsi]"WinNT://$computer/$($_.Name),user")
$pwAge = $user.PasswordAge.Value
$maxPwAge = $user.MaxPasswordAge.Value
$pwLastSet = $now.AddSeconds(-$pwAge)
New-Object -TypeName PSObject -Property #{
'Account Name' = $_.Name
'Disabled' = $_.Disabled
'Password Expires' = $_.PasswordExpires
'Password Last Set' = $pwLastSet
'Password Expiry Date' = $now.AddSeconds($maxPwAge - $pwAge)
'Password Required' = $_.PasswordRequired
'Domain' = $_.Domain
'Password Age' = ($now - $pwLastSet).Days
}
}
If($AccountName)
{
Foreach($Account in $AccountName)
{
$Obj|Where-Object{$_.Name -like "$Account"}
}
}
else
{
$Obj
}
}

Export a custom object to a CSV file only gives me one computer

If I run this it works fine:
$Computers = get-content C:\POSH\test.txt
foreach ($comp in $Computers) {
$CS = Get-WmiObject -Class Win32_computersystem -ComputerName $comp
$Encl = Get-WmiObject -Class Win32_Systemenclosure -ComputerName $comp
$props = #{CompName=$cs.name
Manufacturer=$cs.manufacturer
Model=$cs.model
Serial=$encl.serialnumber}
$obj = New-Object -TypeName PSObject -property $props
Write-Output $obj
}
But if I change write-output $obj to $obj | export-csv c:\posh\test.csv
I only get one computer in the CSV file.
At a quick glance:
It seems you keep overwriting the object you make, by making a new object in each iteration.
You see all $computers on the screen because you use write-output before you repeat the task and overwrite the object. This becomes an issue once you want to combine them.
Otherwise more information might be helpful.
Hello. You can try this:
$obj | export-csv c:\posh\test.csv -Append
Or you can do try:
$Computers = get-content C:\POSH\test.txt
$Computers | % {
$CS = Get-WmiObject -Class Win32_computersystem -ComputerName $_
$Encl = Get-WmiObject -Class Win32_Systemenclosure -ComputerName $_
$obj = New-Object -TypeName psobject -Property #{
CompName=$cs.name
Manufacturer=$cs.manufacturer
Model=$cs.model
Serial=$encl.serialnumber
}
$obj1 = $obj | select -ExpandProperty CompName
$obj2 = $obj | select -ExpandProperty Manufacturer
$obj3 = $obj | select -ExpandProperty Model
$obj4 = $obj | select -ExpandProperty Serial
$out = $obj1 + ";" + $obj2 + ";" + $obj3 + ";" + $obj4
$out >> c:\posh\test.csv
}
$Computers = get-content C:\POSH\test.txt
$obj = foreach ($comp in $Computers) {
$CS = Get-WmiObject -Class Win32_computersystem -ComputerName $comp
$Encl = Get-WmiObject -Class Win32_Systemenclosure -ComputerName $comp
$props = #{CompName=$cs.name
Manufacturer=$cs.manufacturer
Model=$cs.model
Serial=$encl.serialnumber}
New-Object -TypeName PSObject -property $props
}
Write-Output $obj
You are overwriting the $obj variable on each iteration of the loop. So when you export it, it will always only contain the last computer in your list. You can create an array and add each object to it and then output the array to csv.
For example,
$Computers = get-content C:\POSH\test.txt
# Create array to hold all objects
$data = #()
foreach ($comp in $Computers) {
$CS = Get-WmiObject -Class Win32_computersystem -ComputerName $comp
$Encl = Get-WmiObject -Class Win32_Systemenclosure -ComputerName $comp
$props = #{CompName=$cs.name
Manufacturer=$cs.manufacturer
Model=$cs.model
Serial=$encl.serialnumber}
$obj = New-Object -TypeName PSObject -property $props
#Append the object to the array using +=
$data += $obj
}
#Export the objects which were stored in the data array
$data | Export-Csv C:\Test\output.csv -NoTypeInformation

PowerShell - Export Mailbox Statistics to HTML Report

I'm trying to generate a general system report that pulls basic statistics for network hosts. My script works as expected up until the "o365ExchConn" function, whereby it pipes all of the "Import-Pssession" output into the variable that's used to generate the HTML fragment at the end of the script.
How do I exclude this output? I just require the statistics specified in the array within the function. (i.e. Displayname, TotalItemsize & TotalItemCount).
$computername = Read-Host -Prompt "Enter Hostname"
$path = Read-Host -Prompt "Enter path for HTML report output (e.g. C:\Temp)"
$date = Get-Date
function Get-CSInfo {
param($computername)
$os = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $computername
$cs = Get-WmiObject -Class Win32_ComputerSystem -ComputerName $computername
$props = #{‘Hostname’=$computername
‘OS Version’=$os.version
‘OS Build’=$os.buildnumber
‘Service Pack’=$os.sevicepackmajorversion;
'OS Name'=$os.caption}
$obj = New-Object -TypeName PSObject -Property $props
Write-Output $obj
}
function Get-RamInfo {
$os = Get-WmiObject -class Win32_OperatingSystem -ComputerName $ComputerName
$cs = Get-WmiObject -class Win32_ComputerSystem -ComputerName $ComputerName
$props = #{'RAM (GB) - Total Available'="{0:N2}" -f ($cs.totalphysicalmemory / 1GB);
'RAM (GB) - Free for Use'="{0:N2}" -f ($os.freephysicalmemory / 1MB);
'RAM (GB) - Currently in Use'="{0:N2}" -f ($cs.totalphysicalmemory / 1GB) - ($os.freephysicalmemory / 1MB)}
$obj = New-Object -TypeName PSObject -Property $props
Write-Output $obj
}
function Get-InfoDisk {
param($computername)
$drives = Get-WmiObject -class Win32_LogicalDisk -ComputerName $ComputerName -Filter "DriveType=3"
foreach ($drive in $drives) {
$props = #{'Drive'=$drive.DeviceID;
'Size'=$drive.size / 1GB -as [int];
'Free'="{0:N2}" -f ($drive.freespace / 1GB);
'FreePct'=$drive.freespace / $drive.size * 100 -as [int]}
$obj = New-Object -TypeName PSObject -Property $props
Write-Output $obj
}
}
function Get-InfoBadService {
$svcs = Get-WmiObject -class Win32_Service -ComputerName $ComputerName -Filter "StartMode='Auto' AND State<>'Running'"
foreach ($svc in $svcs) {
$props = #{'ServiceName'=$svc.name;
'LogonAccount'=$svc.startname;
'DisplayName'=$svc.displayname}
$obj = New-Object -TypeName PSObject -Property $props
Write-Output $obj
}}
function Get-EventLogs {
$time = (Get-Date) - (New-TimeSpan -Day 1)
$logs = Get-WinEvent -ComputerName $ComputerName -FilterHashTable #{LogName='Application', 'System'; Level=1,2,3; StartTime=$time}
foreach ($log in $logs) {
$props = #{'Provider Name'=$log.ProviderName;
'Timestamp'=$log.TimeCreated;
'Id'=$log.Id;
'Error Type'=$log.LevelDisplayName;
'Message'=$log.Message;
}
$obj = New-Object -TypeName PSObject -Property $props
Write-Output $obj
}
}
function Get-SecurityLogs {
$time = (Get-Date) - (New-TimeSpan -Day 1)
$sec_logs = Get-EventLog -ComputerName $computername -LogName Security -EntryType FailureAudit -After $time
foreach ($sec_log in $sec_logs) {
$props = #{'Timestamp'=$sec_log.TimeGenerated;
'Event ID'=$sec_log.EventID;
'Error Type'=$sec_log.EntryType;
'Message'=$sec_log.Message;
}
$obj = New-Object -TypeName PSObject -Property $props
Write-Output $obj
}
}
function O365ExchConn {
$credentials = Get-Credential
Write-Output "Creating remote PowerShell session ..."
$session = New-PSSession -ConfigurationName Microsoft.Exchange -Credential $credentials -ConnectionUri https://outlook.office365.com/powershell-liveid?DelegatedOrg=*ENTERCOMPANYNAMETENANTNAME* -Authentication Basic -AllowRedirection
Write-Output "Importing PowerShell session ..."
Import-PSSession $session -AllowClobber
$userlist = Get-Mailbox | Get-MailboxStatistics | ft displayname, totalitemsize, itemcount
foreach($user in $userlist){
$props = #{'DisplayName'=$user.displayname;
'Total Size'=$user.totalitemsize;
'Total Items'=$user.itemcount;
}
$obj = New-Object -TypeName PSObject -Property $props
Write-Output $obj
}
}
$frag1 = Get-CSInfo –computername $computername |
ConvertTo-Html -As LIST -Fragment -PreContent ‘<h2>System Info</h2>’ |
Out-String
$frag2 = Get-InfoDisk -ComputerName $computername |
ConvertTo-Html -As Table -Fragment -PreContent '<h2>Disk Info</h2>' |
Out-String
$frag3 = Get-RamInfo -ComputerName $computername |
ConvertTo-Html -As Table -Fragment -PreContent '<h2>Memory Info</h2>' |
Out-String
$frag4 = Get-InfoBadService -ComputerName $computername |
ConvertTo-Html -As Table -Fragment -PreContent '<h2>Stopped Services</h2>' |
Out-String
$frag5 = Get-EventLogs -ComputerName $computername |
ConvertTo-Html -As Table -Fragment -PreContent '<h2>Application / System Logs</h2>' |
Out-String
$frag6 = Get-SecurityLogs -ComputerName $computername |
ConvertTo-Html -As Table -Fragment -PreContent '<h2>Security Logs</h2>' |
Out-String
$frag7 = O365ExchConn -ComputerName $computername |
ConvertTo-Html -As List -Fragment -PreContent '<h2>Exchange Mailbox Stats</h2>' |
Out-String
$head = #’
<style>
body { background-color:#dddddd;
font-family:Tahoma;
font-size:12pt; }
td, th { border:1px solid black;
border-collapse:collapse; }
th { color:white;
background-color:black; }
table, tr, td, th { padding: 2px; margin: 0px }
table { margin-left:50px; }
</style>
‘#
$filepath = Join-Path -Path $path -ChildPath "$computername.html"
ConvertTo-HTML -head $head -PostContent $frag1,$frag2,$frag3,$frag4,$frag5,$frag6,$frag7 -PreContent “<h1>System Maintenance Report for $computername</h1><br><h2>Generated on $date” |
Out-File $filepath
There are multiple ways in PowerShell to prevent cmdlets from outputting text where it's not desired.
See this question for more information
[void] Import-PSSession $session -AllowClobber
Import-PSSession $session -AllowClobber | Out-Null
$ImportPSSession = Import-PSSession $session -AllowClobber

Adding new item into XML output file

I would like to combined the external IP address with the current hardware information output file.
PC info
#lists computer information
$cpu = Get-WmiObject -Class Win32_Processor
$mb = Get-WmiObject -Class Win32_BaseBoard
$bios = Get-WmiObject -Class Win32_BIOS -ComputerName .
#$user = Get-WmiObject -Class Win32_ComputerSystem
$last = Get-WmiObject -class Win32_NetworkLoginProfile |
Where {($_.NumberOfLogons -gt 0) -and ($_.NumberOfLogons -lt 65535)} |
Select-Object Name,#{label='LastLogon';expression={$_.ConvertToDateTime($_.LastLogon)}},NumberOfLogons
$props = #{
"Name" = $cpu.Name
"Description" = $cpu.Description
"MB Manufacturer" = $mb.Manufacturer
"MB Product" = $mb.Product
"Bios Verison" = $bios.SMBIOSBIOSVersion
"Bios Manufacturer" = $bios.Manufacturer
"Bios Serial" = $bios.SerialNumber
"~Last Logon" = $last
}
New-Object PSObject -Property $props | Out-File c:\Windows\Script\PS_Output3.xml
External IP Address
$wc=New-Object net.webclient;
$wc.downloadstring("http://checkip.dyndns.com") -replace "[^\d\.]"
Update
One last question: how could I organize the list?
Something like this might help:
#lists computer information
$cpu = Get-WmiObject -Class Win32_Processor
$mb = Get-WmiObject -Class Win32_BaseBoard
$bios = Get-WmiObject -Class Win32_BIOS -ComputerName .
#$user = Get-WmiObject -Class Win32_ComputerSystem
$DyDNS = Invoke-WebRequest http://checkip.dyndns.com/ -DisableKeepAlive
$Dyreg = $DyDNS.RawContent -match '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b'
$last = Get-WmiObject -class Win32_NetworkLoginProfile | Where {($_.NumberOfLogons -gt 0) -and ($_.NumberOfLogons -lt 65535)} | Select-Object Name,#{label='LastLogon';expression={$_.ConvertToDateTime($_.LastLogon)}},NumberOfLogons
$props = #{
"Name" = $cpu.Name
"Description" = $cpu.Description
"MB Manufacturer" = $mb.Manufacturer
"MB Product" = $mb.Product
"Bios Verison" = $bios.SMBIOSBIOSVersion
"Bios Manufacturer" = $bios.Manufacturer
"Bios Serial" = $bios.SerialNumber
"~Last Logon" = $last
"DNS" = $matches[0]
}
New-Object PSObject -Property $props | Out-File C:\test.csv