Adding a config file to loop through for a PS script - powershell

My powershell script is setup as follows:
$body = Get-ChildItem E:\log -File -Recurse | Where Name -Match '(\d{8})\.' |
Foreach {Add-Member -Inp $_ NoteProperty ReturnDate ($matches[1]) -PassThru} |
Group DirectoryName |
Foreach {$_.Group | Sort ReturnDate -Desc | Select -First 1 | Out-String }
$emailSmtpServer = "server"
$emailFrom = "email"
$emailTo = "email"
$emailSubject = "Testing e-mail"
$emailBody = $body
Send-MailMessage -To $emailTo -From $emailFrom -Subject $emailSubject -Body ($body|Out-String) -SmtpServer $emailSmtpServer
In the log folder I have a bunch of subfolders, e.g. folder1, folder2, folder3. These are likely to change so I'd like to setup a config file to be able to maintain them instead of going through the entire E:\log folder each time I run the script.
I want to add something such as
$configfile = Get-Content -path E:\config.txt
This outputs Process1, Process2, Process3, etc and I'm uncertain how to put that data into my script the way it's currently structured. Any advice would be appreciated. I was trying to add
$body = Get-Childitem E:\log\$_
to my initial line, but that was not working

Try this:
get-childitem ( get-content e:/config.txt )

Related

How to attach files to email using Get-ChildItem in Powershell

I am trying to write a Powershell script that does the following:
Check all files in a directory for a valid string
Take every file that contains that valid string and then send them as an email attachment
I do not care if one email is sent with all of the valid files or if an email is sent for each valid file.
The following code is what I have but it errors out when trying to attach the files saying Send-MailMessage : Cannot find drive. A drive with the name '
$ValidFiles = Get-ChildItem -Path C:\Results -Recurse |
Select-String -Pattern "Test" |
Select-Object -Unique Path
foreach ($ValidFile in $ValidFiles)
{
$From = 'test <test#test.com>'
$To = 'me <me#test.com>'
$Subject = "Valid File Found"
$Username = "Test-Domain\test"
$Password = ConvertTo-SecureString "notrealpassword" -AsPlainText -Force
$Creds = New-Object System.Management.Automation.PSCredential($username, $password)
$Body = "Please review the attached files"
$Attachment = $ValidFile | Out-String
$SMTPServer = "test-com.mail.protection.outlook.com"
Send-MailMessage -From $From -To $To -Subject $Subject -Credential ($Creds) -Attachments $Attachment -UseSsl -Body $Body -DeliveryNotificationOption OnSuccess, OnFailure -SmtpServer $SMTPServer
}
Any help is greatly appreciated.
First, make sure that $ValidFiles contains only strings (file paths):
$ValidFiles = Get-ChildItem -Path C:\Results -Recurse |
Select-String -List -Pattern "Test" |
ForEach-Object Path
Adding -List to Select-String makes the search stop at the first match found in a given file, which obviates the need for Select-Object -Unique.
Select-Object outputs [pscustomobject] instances with the specified property/properties, even if only one property Path is specified; while you could use -ExpandProperty Path instead to get just the .Path property value, it is simpler to use ForEach-Object with the property name instead.
Then, use $ValidFile - which is now a path string - directly as the -Attachments argument (which is [string[]]-typed, but also accepts a scalar [string] instance (single string)).
Generally, do not use Out-String, unless you want a formatted for display representation of the input object(s).
Out-string stops $Attachment from getting populated.
$Attachment = $ValidFile | Out-String
Try
$Attachment = $ValidFile

Sending foreach output via email

I have a script that is checking mirror status of databases. Output in Powershell is fine, but when I try to send it via mail, I'm getting "Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData" instead of data itself. I've tried to change it to Out-String but then I'm getting all results in one line. How this could be done to have formated output the same way as it is formated directly in PowerShell?
# rozszerzenie do obslugi
[System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SqlServer.Smo") | Out-Null;
$mail_from = "xxx";
$mail_to = "xxx";
$mail_subject = "Status mirrorowanych baz";
$mail_encoding = "UTF8";
$mail_smtp = "xxx";
# lista serwerow
$list = #("SERVER01V",
"SERVER02V"
);
$output = foreach($server in $list)
{
$srv = New-Object "Microsoft.SqlServer.Management.Smo.Server" $server;
# pokaz tylko mirrorowane
$databases = $srv.Databases | Where-Object {$_.IsMirroringEnabled -eq $true};
Write-Output "<br>==================================<br>";
Write-Output $server;
Write-Output "<br>==================================<br>";
$databases | Select-Object -Property Name, MirroringStatus | Format-Table -AutoSize | Out-String;
Write-Output "<br>";
}
$mail_body = $output;
Send-MailMessage -To $mail_to -From $mail_from -Subject $mail_subject -SmtpServer $mail_smtp -Encoding $mail_encoding -Body $mail_body -BodyAsHtml
You're currently sending a HTML mail. As such line breaks won't matter. If you want line breaks in your mail you either need to use text format or replace line breaks with a <br /> or something similar. It's probably going to be wise to have manually add <br /> in your look to have a consistent pattern and replace.
Try gather all data into an array, then use ConvertTo-HTML cmdlet, and the 'BodyAsHTML' switch in Send-MailMessage
$DatabaseArray=#()
ForEach ($server in $list) {
$srv = New-Object "Microsoft.SqlServer.Management.Smo.Server" $server
$DatabaseArray += $srv.Databases | Where-Object {$_.IsMirroringEnabled -eq $true} | Select-Object Name,MirroringStatus
}
$HTMLBody = $DatabaseArray | ConvertTo-HTML
Send-MailMessage -subject x -body $HTMLBody -BodyAsHTML

Powershell search for longfile path names and send the owner of a file a mail to do something about it

I am trying to set up a PowerShell script which reads out a UNC path on Windows and searches for longfiles/paths. After it has found the file it needs to send a mail to the owner of the file.
I have found already a script and tweaked it a bit but it doesn't seems to work yet. The following script can find the long file path now but the mail is not working properly.
$limit = 90
$testpath = "C:\test"
$resultpath = "c:\test"
$admins = "moh#test.com"
$from = "moh#test.com"
$smtpserver = "smtp.office365.com"
Get-ChildItem -Path $testpath -Recurse | ?{$_.fullname.length -gt $limit} |
Select-Object fullname,
#{n="owner";e={
$_.GetAccessControl().GetOwner('System.Security.Principal.NTAccount')}},
#{n="namelength"; e={$_.fullname.length}} |
%{
Out-File -FilePath "$resultpath\Longfiles of $($_.owner -replace "\\","-").txt" -Append -InputObject "$($_.namelength) - $($_.fullname)"
}
Get-ChildItem $resultpath -Filter "longfiles of *" | % {
if($_.name -match "Longfiles\sof\s(.+)\.txt"){
$user = $matches[1] -replace "-","\"
$ntacc = New-Object System.Security.Principal.NTAccount($user)
$sid = $ntacc.Translate([System.Security.Principal.SecurityIdentifier])
$aduser = [ADSI]"LDAP://<SID=$sid>"
$email = $aduser.Properties.mail
if($email) {Send-MailMessage -Attachments $_.fullname -Body "Please change the filenames of the files listed in the attached file to shorter!"
-From $from -SmtpServer $smtpserver -Subject "System notice" -To
$email -cc $admins
}
else {
Send-MailMessage -Attachments $_.fullname -Body "email coudn't be sent to owner" `
-From $from -SmtpServer $smtpserver -Subject "System notice" -To $admins
}
}
else {Write-Host "Some error with file $_"}
}
EDIT: This is what i see, after running the script... it is asking me to fill in the fields, while the fields are already filled in in the script such as (From: moh#test.com to moh#test.com)
[]
You issue was because of line breaks in the middle of a command. In some lines, you had a backtick character which escapes the end of the line. But as you found these are really easy to break and that's why it's best practice to use splatting on commands with many parameters.
I also changed your Select-Object calculated properties into a more readable [pscustomobject] since they are hard to format in a readable way, but this does require PS3+.
$limit = 90
$testpath = "C:\test"
$resultpath = "c:\test"
$admins = "moh#test.com"
$from = "moh#test.com"
$smtpserver = "smtp.office365.com"
Get-ChildItem -Path $testpath -Recurse |
Where-Object {$_.fullname.length -gt $limit} |
ForEach-Object {
[PSCustomObject]#{
'fullname' = $_.fullname
'owner' = $_.GetAccessControl().GetOwner('System.Security.Principal.NTAccount')
'namelength' = $_.fullname.length
}
} |
ForEach-Object {
Out-File -FilePath "$resultpath\Longfiles of $($_.owner -replace "\\","-").txt" -Append -InputObject "$($_.namelength) - $($_.fullname)"
}
Get-ChildItem $resultpath -Filter "longfiles of *" | ForEach-Object {
if ($_.name -match "Longfiles\sof\s(.+)\.txt") {
$user = $matches[1] -replace "-", "\"
$ntacc = New-Object System.Security.Principal.NTAccount($user)
$sid = $ntacc.Translate([System.Security.Principal.SecurityIdentifier])
$aduser = [ADSI]"LDAP://<SID=$sid>"
$email = $aduser.Properties.mail
if ($email) {
$mailparams = #{
'Attachments' = $_.fullname
'Body' = "Please change the filenames of the files listed in the attached file to shorter!"
'From' = $from
'SmtpServer' = $smtpserver
'Subject' = "System notice"
'To' = $email
'cc' = $admins
}
Send-MailMessage #mailparams
} else {
$mailparams = #{
'Attachments' = $_.fullname
'Body' = "email coudn't be sent to owner"
'From' = $from
'SmtpServer' = $smtpserver
'Subject' = "System notice"
'To' = $admins
}
Send-MailMessage #mailparams
}
} else {
Write-Host "Some error with file $_"
}
}
Remove the line breaks or escape them with a backtick: `. Your script must actually look like this:
if ($email) {
Send-MailMessage -Attachments $_.fullname -Body "Please change the filenames of the files listed in the attached file to shorter!"
-From $from -SmtpServer $smtpserver -Subject "System notice" -To
$email -cc $admins
}
else {
Send-MailMessage -Attachments $_.fullname -Body "email coudn't be sent to owner" `
-From $from -SmtpServer $smtpserver -Subject "System notice" -To $admins
}
And Powershell doesn't know that the line beginning with -From is part of Send-MailMessage.

$FormatEnumerationLimit = -1 within a PowerShell script

I have created a PowerShell script, but the output gets cut off with ...}
If I type $FormatEnumerationLimit = -1 before I run the script, it works. But the problem is I can't seem to include this command within my script. If I add this command at the top of my script, it doesn't work.
How can I get this included in the script?? Sorry I don't think the script copied over correctly in the window.
$FormatEnumerationLimit = -1
Get-ChildItem hklm:\SOFTWARE\Wow6432Node\software\nameofsoftware | ForEach- Object {
Get-ItemProperty $_.pspath
} | Foreach-Object {
$Properties = #{
Name = $_.Name
Header= $_.Header
True= $_.True
Schedule = $_.Schedule
}
New-Object -TypeName PSObject -Property $Properties
} | FL | Out-File C:\test.txt -Width 10000
Send-MailMessage -from "joe#joe.com" -to "joe#joe.com" -subject "Test"
-smtpserver 192.168.5.2 -port 25 -Attachments C:\test.txt
FL output is meant for the screen, rather than for files. Besides, why package all the information up to an object only to try and take it apart immediately? You could output the information in the format you want, directly:
} | Foreach-Object {
"Name: " + $_.Name
"Header: " + $_.Header
"True: " + $_.True
"Schedule: " + $_.Schedule
} | Set-Content C:\test.txt

Powershell Script to Monitor Folder Space

I have written a script which monitors specific folder space monitoring and it alerts me once it crosses the threshold. Issue what i am facing is with multiple servers in place i am getting multiple emails so is it possible that we can consolidate the results in one mail having all servers which having issue. Below is script:-
$servers = Get-Content C:\server.txt
$folder = "D$\store\"
$smtpserver = "XXXXXX"
#(
foreach ($Server in $Servers)
{
$folderSize = ( Get-ChildItem -path \\$server\$folder -Recurse -Force | Measure-Object -Property Length -Sum ).Sum
if ($folderSize -gt '60Gb') {
Write-output "Folder size exceeded 60 GB on server:-$Server. Current size on $server is $folderSize. Please review and take further action." | Out-file -FilePath "C:\reslt.txt"
Send-MailMessage -to abc#abc.com -from xx#xx.com -Subject "Limit Alert" -SmtpServer $smtpserver -Attachments "C:\reslt.txt"
}
else { Write-output "Folder size is within 60GB on $server." }})
You should post what you've tried. That being said, here's a start, written in notepad, so excuse any slight issues. You should probably just take results and instead of iterating over them, make them into a table, set the email to be HTML, and put the result of the table converted into an HTML snippet into the body of the message.
$servers = Get-Content C:\server.txt
$folder = "D$\store\"
$smtpserver = "XXXXXX"
$results = #()
foreach ($Server in $Servers) {
$folderSize = ( Get-ChildItem -path \\$server\$folder -Recurse -Force | Measure-Object -Property Length -Sum ).Sum
if ($folderSize -gt '60Gb') {
Write-Output "Folder size exceeded limit on $server"
$results += New-Object -TypeName PSObject -Property #{
ServerName = $Server
FolderSize = $folderSize
}
}
else { Write-output "Folder size is within 60GB on $server." }
}
if ($results.Count -gt 0){
$bodyString = "Servers over limit:"
#I'd get fancy here and take $results, format it as a table, and then convert to HTML and put the snippet in the body...
$results | % {$bodyString += "The server "+$_.ServerName+"is over the limit and is currently at "+$_.FolderSize+"GB`r`n"}
Send-MailMessage -to abc#abc.com -from xx#xx.com -Subject "Limit Alert" -SmtpServer $smtpserver -Body $bodyString
}
else {
Send-MailMessage -to abc#abc.com -from xx#xx.com -Subject "Limit Alert - no results" -SmtpServer $smtpserver -Body "No results were found for servers over the limit"
}