Example 94 shows how to easily send email messages from your scripts.
In addition to the fields shown in the script, the System.Net.Mail.MailMessage class supports properties that let you add attachments, set message priority, and much more.
Example 94. SendMailMessage.ps1
############################################################################## ## ## SendMailMessage.ps1 ## ## Illustrate the techniques used to send an email in PowerShell. ## ## Example: ## ## PS >$body = @" ## >> Hi from another satisfied customer of The PowerShell Cookbook! ## >> "@ ## >> ## PS >$to = "guide_feedback@leeholmes.com" ## PS >$subject = "Thanks for all of the scripts." ## PS >$mailHost = "mail.leeholmes.com" ## PS >SendMailMessage $to $subject $body $mailHost ## ##############################################################################
param( [string[]] $to = $(throw "Please specify the destination mail address"), [string] $subject = "<No Subject>", [string] $body = $(throw "Please specify the message content"), [string] $smtpHost = $(throw "Please specify a mail server."), [string] $from = "$($env:UserName)@example.com"
)
## Create the mail message $email = NewObject System.Net.Mail.MailMessage
## Populate its fields foreach($mailTo in $to) {
$email.To.Add($mailTo) }
$email.From = $from $email.Subject = $subject $email.Body = $body
## Send the mail $client = NewObject System.Net.Mail.SmtpClient $smtpHost $client.UseDefaultCredentials = $true $client.Send($email)
Program: Interact with Internet Protocols in Windows PowerShell
While it is common to work at an abstract level with web sites and web services, an entirely separate style of Internetenabled scripting comes from interacting with the remote computer at a much lower level. This lower level (called the TCP level, for Transmission Control Protocol) forms the communication foundation of most Internet protocols—such as Telnet, SMTP (sending mail), POP3 (receiving mail), and HTTP (retrieving web content).
The .NET Framework provides classes that allow you to interact with many of the Internet protocols directly: the System.Web.Mail.SmtpMail class for SMTP, the System.Net.WebClient class for HTTP, and a few others. When the .NET Framework does not support an Internet protocol that you need, though, you can often script the application protocol directly if you know the details of how it works.
Example 95 shows how to receive information about mail waiting in a remote POP3 mailbox, using the SendTcpRequest script given in Example 96.
Example 95. Interacting with a remote POP3 mailbox
## Get the user credential if(not (TestPath Variable:\mailCredential)) {
$mailCredential = GetCredential } $address = $mailCredential.UserName $password = $mailCredential.GetNetworkCredential().Password
## Connect to the remote computer, send the commands, and receive the ## output $pop3Commands = "USER $address","PASS $password","STAT","QUIT" $output = $pop3Commands | SendTcpRequest mail.myserver.com 110 $inbox = $output.Split("`n")[3]
## Parse the output for the number of messages waiting and total bytes $status = $inbox |
ConvertTextObject PropertyName "Response","Waiting","BytesTotal","Extra" "{0} messages waiting, totaling {1} bytes." f $status.Waiting, $status.BytesTotal
In Example 95, you connect to port 110 of the remote mail server. You then issue commands to request the status of the mailbox in a form that the mail server understands. The format of this network conversation is specified and required by the standard POP3 protocol. Example 95 uses the ConvertTextObject command
Example 96 supports the core functionality of Example 95. It lets you easily work with plaintext TCP protocols.
Example 96. SendTcpRequest.ps1
############################################################################## ## SendTcpRequest.ps1 ## ## Send a TCP request to a remote computer, and return the response. ## If you do not supply input to this script (via either the pipeline, or the ## InputObject parameter,) the script operates in interactive mode. ## ## Example:
##
##
$http = @"
##
GET / HTTP/1.1
##
Host:search.msn.com
##
`n`n
##
"@
##
##
$http | SendTcpRequest search.msn.com 80
##############################################################################
param( [string] $remoteHost = "localhost", [int] $port = 80, [string] $inputObject, [int] $commandDelay = 100
)
[string] $output = ""
## Store the input into an array that we can scan over. If there was no input, ## then we will be in interactive mode. $currentInput = $inputObject if(not $currentInput) {
$SCRIPT:currentInput = @($input) } $scriptedMode = [bool] $currentInput
function Main
{ ## Open the socket, and connect to the computer on the specified port if(not $scriptedMode) {
WriteHost "Connecting to $remoteHost on port $port" }
trap { WriteError "Could not connect to remote computer: $_"; exit } $socket = NewObject System.Net.Sockets.TcpClient($remoteHost, $port)
if(not $scriptedMode) { WriteHost "Connected. Press ^D followed by [ENTER] to exit.`n" }
$stream = $socket.GetStream() $writer = NewObject System.IO.StreamWriter($stream)
Example 96. SendTcpRequest.ps1 (continued)
## Create a buffer to receive the response $buffer = NewObject System.Byte[] 1024 $encoding = NewObject System.Text.AsciiEncoding
while($true)
{ ## Receive the output that has buffered so far $SCRIPT:output += GetOutput
## If we're in scripted mode, send the commands, ## receive the output, and exit. if($scriptedMode) {
foreach($line in $currentInput)
{ $writer.WriteLine($line) $writer.Flush() StartSleep m $commandDelay $SCRIPT:output += GetOutput
}
break } ## If we're in interactive mode, write the buffered ## output, and respond to input. else {
if($output)
{ foreach($line in $output.Split("`n")) {
WriteHost $line } $SCRIPT:output = ""
}
## Read the user's command, quitting if they hit ^D $command = ReadHost if($command eq ([char] 4)) { break; }
## Otherwise, write their command to the remote host $writer.WriteLine($command) $writer.Flush()
} }
## Close the streams $writer.Close() $stream.Close()
Example 96. SendTcpRequest.ps1 (continued)
## If we're in scripted mode, return the output if($scriptedMode) {
$output } }
## Read output from a remote host function GetOutput {
$outputBuffer = "" $foundMore = $false
## Read all the data available from the stream, writing it to the ## output buffer when done. do {
## Allow data to buffer for a bit StartSleep m 1000
## Read what data is available $foundmore = $false while($stream.DataAvailable) {
$read = $stream.Read($buffer, 0, 1024) $outputBuffer += ($encoding.GetString($buffer, 0, $read)) $foundmore = $true
} } while($foundmore)
$outputBuffer }
. Main
Code Reuse in PowerShell
What surprises many people is how much you can accomplish in PowerShell from the interactive prompt alone. Since PowerShell makes it so easy to join its powerful commands together into even more powerful combinations, enthusiasts grow to relish this brevity. In fact, there is a special place in the heart of most scripting enthusiasts set aside entirely for the most compact expressions of power: oneliners.
Despite its interactive efficiency, you obviously don’t want to retype all your brilliant ideas anew each time you need them. When you want to save or reuse the commands that you’ve written, PowerShell provides many avenues to support you: scripts, libraries, functions, script blocks, and more.