Clicky

20240701

Select file and email to yourself with one click

My current attachment emailscript uses the MailMessage method, but this method is obsolete (see: https://github.com/dotnet/platform-compat/blob/master/docs/DE0005.md). So I followed the recommendation, and used the MailKit Powershell Module to send emails.

Updates:

  1. Use of MailKit to send emails (requires installation of the MailKit Powershell Module).
  2. Added an "Install" procedure. Automate user settings.
  3. Added a "setPassword" procedure. Secure password entry and password storage in USERPROFILE (no plain text password anywhere).

Works with:

  • Windows Explorer Context menu (right click file and send email)
  • Command line (file parameter must have absolute/complete file path)
  • Drag and drop (create a Deaktop shortcut to the psEmailAttachment.ps1 script and drag a file to the shortcut be emailed)

 Installation procedure:

  1. Install the MailKit Module (e.g.: PS C:\> Install-Module -force -Name "Send-MailKitMessage" -Scope CurrentUser)
  2. Store the psEmailAttachment.ps1 script in some folder
  3. Update the email server properties and your email address in the psEmailAttachment.ps1 script
  4. Run:
    • Powershell -file psEmailAttachment.ps1 -install     #--- Create the Explorer context menu entry
    • Powershell -file psEmailAttachment.ps1 -setPassword #--- Setting the password of the email sender account.
Done.

Sending an email from Windows Explorer-> Right click filename:

psEmailAttachment.ps1

using module Send-MailKitMessage
<#

    To install the MailKit:
    PS C:\> Install-Module -force -Name "Send-MailKitMessage" -Scope CurrentUser #--- Install Module only for this user. User privileges only.
   
    Or:
    PS C:\> Install-Module -force -Name "Send-MailKitMessage" -Scope AllUsers           #--- Install Module for all users. Administrative privileges needed.
   
    Emailing examples shamelessly stolen from: https://github.com/austineric/Send-MailKitMessage

#>

param(
    [SWITCH]$install,
    [SWITCH]$setPassword
)    
   
#--- User variables...
$SMTPServer         = "{FQDN or IP address from email server}"
$Port               = 587 #---> STARTTLS or 465 SSL/TLS...
$emailSenderAccount = "emailAttachment@ddress.ext"
$To                 = "yourEmail@ddress.ext"


#=== MAIN =====================================================================================================
#--- Static variables...
$TextBody           = "Attachment sent with $($MyInvocation.MyCommand.Path) script."
$scriptPath         = $MyInvocation.MyCommand.Path

#--- Create password filename in AppData...
$scriptName         = (Get-Item $scriptPath).Basename
$appDataFolder      = "$ENV:USERPROFILE\AppData\Local\$scriptName"
new-item -type directory -path $appDataFolder -force | out-null
$smtpPasswordFile   = "$appDataFolder\$emailSenderAccount-password.dat"

if ($setPassword) {

    write-host "*** Setting encrypted password..."
   
    #--- Read and store encrypted password in $smtpPasswordFile...
    $readPassword     = Read-Host -assecurestring "Enter sender email account's ($($emailSenderAccount)) password now"
    $password         = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($readPassword))
    $password | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString | Out-File $smtpPasswordFile
    $password         = $null
   
    write-host "*** Ready."
    Exit
   
}


if ($install) {
   
    #--- Note: writing in "HKEY_CLASSES_ROOT" requires Administrative privileges...
   
    #--- Some Powershell Registry black magic, setting Windows Explorer context menu...
    write-host "*** Setting Explorer context menu settings..."
    new-item         -Path Registry::"HKCR\``*\Shell"              -Name "Email to $To" -force | out-null
    set-ItemProperty -Path Registry::"HKCR\``*\Shell\Email to $To" -Name "Icon"    -Value "%systemroot%\system32\dsuiext.dll,16" -force | out-null
    new-item         -Path Registry::"HKCR\``*\Shell\Email to $To" -Name "command" -Value "powershell -ExecutionPolicy Bypass -noprofile -file ""$scriptPath"" ""%1"" " -force | out-null
   
    write-host "*** Right-click a filename in Windows Explorer and select: 'Email to $To'"
    write-host "*** Ready."
    Exit
   
}    


if ($args.count -EQ 0) {
   
    write-host "*** No attachment data provided."
    break
   
}    


#--- From...
$From = [MimeKit.MailboxAddress]$emailSenderAccount
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $emailSenderAccount, (Get-Content $smtpPasswordFile | ConvertTo-SecureString)

#--- To...
$RecipientList = [MimeKit.InternetAddressList]::new()
$RecipientList.Add([MimeKit.InternetAddress]$To)

#--- Attachment...
$Attachment = $args[0]
$AttachmentList = [System.Collections.Generic.List[string]]::new()
$AttachmentList.Add($Attachment)
$Subject = "Attachment: $Attachment"

#--- Send email...
write-host "*** Emailing attchment '$Attachment' to $To..."
$UseSecureConnectionIfAvailable = $true
Send-MailKitMessage -SMTPserver $SMTPServer -Credential $Credential -Port $Port -From $From -RecipientList $RecipientList -Subject $Subject -textBody $TextBody -AttachmentList $AttachmentList
write-host "*** Ready."

start-sleep 2

 

20240330

psEmailScreenshot.ps1: Email a screenshot

The next script takes a screenshot and sends the screenshot as PNG file to your emailaddress.

You need to "install" the script. The installation will copy the script to the user's "appdata" folder. This allows the script also to work on restricted desktops, e.g., on managed desktops. 

Also, you need to enter the email sender account password. The password will be stored encoded in the same folder as the script. There is no plaintext password shown or stored, no other user can (re-)use this password file, and copying the password file to another PC will not work.

 

Install:

C:\Temp\> powershell -file psEmailScreenshot.ps1 install

The installation will create a shortcut on your desktop:


The script can (also) be invoked with the shortcut keys: CTRL+ALT+S

 

Set password:

C:\Temp\> powershell -file psEmailScreenshot.ps1 setpassword

 

The complete setup procedure will look this:





 

 

 


The script: psEmailScreenshot.ps1:

#--- User variables...
$SMTPServer       = "{IP or FQDN to mailserver}"
[INT]$SMTPport    = 587 #--- STARTTLS
$smtpUser         = "{emailSenderAccount@domain.ext}"
$EmailFrom        = "{emailscreenshot@domain.ext}"
$EmailTo          = "{receiver@domain.ext}"

#--- MAIN ------------------------------------------------------------------------------------------
if ($args.count -NE 1) {

    Break

}

$scriptFilename   = $MyInvocation.MyCommand.Path
$scriptName       = $MyInvocation.MyCommand
$scriptFolder     = "$home\appdata\Local\mailScreenshot"
$smtpPasswordFile = "$scriptFolder\EmailPassword.txt"

if (!(test-path $scriptFolder)) {

    New-Item $scriptFolder -ItemType Directory | out-null

}


if ($($args[0]).toLower() -EQ "install")
{

    #--- Copy the PS file to %appdata% and create a Shortcut on the Desktop with a HotKey...
    copy-item $scriptFilename "$scriptFolder\$scriptName" -force | out-null

    #--- Create shortcut...
    $iconFile              = "$home\Desktop\Email Screenshot.lnk"
    $wsh                   = New-Object -comObject WScript.Shell
    $Shortcut              = $wsh.CreateShortcut($iconFile)
    $Shortcut.TargetPath   = "powershell"
    $shortcut.Arguments    = " -file $scriptFolder\$scriptName emailscreenshot"
    $shortcut.IconLocation = "SHELL32.dll,24"
    $shortcut.HotKey       = "CTRL+ALT+S"
    $shortcut.WindowStyle  = 7 #--- 7 => hidden
    $Shortcut.Save()
   
    write-host "*** Shortcut: '$iconFile'"
    write-host "*** Keyboard shortcut: CTRL+ALT+S"
    write-host "*** $scriptName is installed."

    Exit

}

#--- Store the SMTP sender's password as SecureString. Note: this password is bound to the %USERPROFILE%...
if ($($args[0]).toLower() -EQ "setpassword") {

    $password = Read-Host -assecurestring "Enter sender email account's password now"
    $password = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password))
    $password | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString | Out-File $smtpPasswordFile
    $password = $null

    Exit

}

#--- Take screenshot...
Add-Type -AssemblyName System.Windows.Forms
$screenProperties = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds
$imageObject      = New-Object System.Drawing.Bitmap($screenProperties.Width, $screenProperties.Height)
$graphic          = [System.Drawing.Graphics]::FromImage($imageObject)
$point            = New-Object System.Drawing.Point(0, 0)
$graphic.CopyFromScreen($point, $point, $imageObject.Size);

#--- Yes/No dialog...
$wshell = New-Object -ComObject Wscript.Shell
$answer = $wshell.Popup("Email screenshot.",10,"Send screenshot to: $EmailTo ?",4+32)

if ($answer -EQ 6) {

    #--- Convert Bitmap to PNG and store in %TEMP%...
    $screenPropertiesshotFilename = "$($env:temp)\" + $env:computername + "_" + $env:username + "_" + "$((get-date).tostring('yyyy.MM.dd-HH.mm.ss')).png"
   
    #--- Bitmap memory to PNG: https://stackoverflow.com/questions/3517965/convert-bmp-to-png-in-memory-for-clipboard-pasting-in-net
    $imageObject.Save($screenPropertiesshotFilename, [System.Drawing.Imaging.ImageFormat]::Png)

    #--- Email the screenshot file..
    $MailSubject    = "Screenshot from computer: $($env:computername), user: $($env:username)"
    $Credentials    = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $smtpUser, (Get-Content $smtpPasswordFile | ConvertTo-SecureString)
    Send-MailMessage -To "$emailTo" -from "$emailFrom" -Subject $MailSubject -SmtpServer $SmtpServer -UseSsl -Credential $Credentials -Attachment $screenPropertiesshotFilename

    #--- Cleanup...
    remove-item $screenPropertiesshotFilename -force

}



Note: the "Send-MailMessage" method is depricated. See here for additional information: https://github.com/dotnet/platform-compat/blob/master/docs/DE0005.md

 

20240326

Bose QuietComfort Ultra improvements

Bose QuietComfort Ultra buds are the best ANC buds by far. Second to none. 

But, I wanted to improve things, since my dear girlfriend did left my old Bose QuietComfort II's in the trousers of my pants and put them in the washing machine, I had to buy new ANC buds. So here are a couple of improvements. Take your pick.

Improvements:

#1. White buds instead of the black ones (actually, the Ultra's are light grey). When you drop the case, the buds might jump out and black buds may be hard to find.

#2. Prevent the case to jump open, e.g., when you drop the case. 

Solution: take a leather strap, attach one end of the strap with doublesided tape to the case and use self-adhesive Velcro at the other end to lock/unlock the case.


#3. Distinct between left and right bud when you place them back in the case.

Solution: use a little nail polish to mark one. I used [R]ed for [R]ight

#4. Add "Find my device" info

Solution: use a label maker to add an email addres and a phone number. E.g., this method once returned a forgotten tablet at the gym to me.

All improvements can be rolled back. Take care with nailpolish remover. Use a cotton swab to gently remove the Right/Left marker(s).


20240310

Rotel RC-1570 bad flash recovery

Update 30-Mar-2024.

At the end of the day the problems started with a bad USB - RS-232 adapter. This adapter had a counterfeit CH340 chip, which created the initial firmware update problems. These counterfeit chips are found in cheap Chinese USB to 9p DIN adapters. Penny wise, pound foolish!

So, when the Rotel YMODEM software shows garbled output, like this, try another RS-232 adapter or maybe even a different PC to update the Rotel firmware.

Garbled output due to bad USB - RS-232 adapter.

--------------------------------------------------------------------------------------------------------------------------

This post is about fixing a Rotel RC-1570 bad flash due to a broken RS-232 interface.


Warning/disclaimer: when you start digging in the hard- and software of your device, you may easily break the device beyond repair. I do not and will not take any responsibility for this. You are on your own. 

Requirement: upgrade the firmware of the amplifier.

You *should* use the Rotel Firmware update software ("ROTEL YModem Upgrade Manager V203.exe". See link below). This Windows application is a YMODEM protocol shell to program the CPU's firmware through the RS-232 port. It tries to figure out the Rotel device type and allows to select the new firmware from disk, and program it. Comprehensive feedback is provided on the state of the upgrade.

When the Rotel Firmware software works, you are done. Nothing to see here, walk over. In case something fails, or the amplifier is dead, read on!

So, I bought a second-hand Rotel RC-1570 pre-amp. Basically, an input device selector, DAC (S/PDIF + Coax), a PC USB interface and the NE5532 opamp based pre-amplifier. 

I started to upgrade the firmware to the latest version. The firmware upgrade is done using the RS-232 9 Pin D-connector at the back of the device. You need to get a 9p D to USB adapter, which is supported by your Windows PC (drivers). When you connect the RS-232 adapter and you configure the COM port settings as 115200/8/n/1, you will see some output appear on the console program.

Problem statement:
1. The RS-232 out shows garbled characters.
2. A previous flash exercise left the device in a "dead" state.

After the failed flash the device seems dead as a dodo. No light, no display, no relay clicks, no nothing. Connecting a terminal emulator (PuTTY, Tera Term) there was garbled output shown. The garbled out still showed "readable" words.

Step 1: Diagnosing the garbled data

The garbled data with readable words is an important symptom because this means that the CPU/software/firmware was most likely working, and that we had a data transmission problem.

The RS-232 adapter is on a separate module together with other Rotel signalling:


 

The module is connected to the motherboard with connector CN207. This is the data path of the RS-232 data to the CPU of the Rotel (click to enlarge):

 

 

On the righthand side you find the RS-232 input. IC205 converts RS-232 signal voltage to 3VDC and back. The input/output signals are directly connected to the CPU (pin 68 and 69). When we use an adapter with 3VDC levels, we do not have to use the RS-232 board. 

We disconnected connector CN207 and used a spare connector/cable to connect a USB-TTL adapter.

 


The only pins we needed are 1 (RX, Rotel in, red wire), 2 (TX, Rotel out, white wire) and 3 (Ground, green wire). We connected a standard CH340E chip USB-TTL adapter to the 3 pins:

After powering up the device, all console output shown was correct. Conclusion: the RS-232 interface is broken. At this point the "ROTEL YModem Upgrade Manager V203" software should work. The Rotel can be flashed again.

However, since the Rotel software is a YMODEM shell, we took a different approach to flash the CPU.

Step 2: Flashing the firmware with YMODEM

Terminal emulator Tera Term (see links below) has build-in YMODEM support. Still having the USB-TTL adapter connected, we powered on the Rotel. The Rotel STM32 flash menu is shown:


Select "1" and watch "C" characters appear. This is the start of the YMODEM upload. In the Tera Term menu select  File -> Transfer -> YMODEM -> Send and select the Rotel firmware (here: "RA1570-V138-Ymodem.bin"). A progress bar is shown, and after completion of the upload you will see this:

After power down and power up, the Rotel came alive again! 

Since YMODEM is a relativly simple protocol, I guess that YMODEM upload, in this case with Tera Term, should work for al Rotel STM32 CPU related firmware updates. However, the use of the  "ROTEL YModem Upgrade Manager V203" software is perferred.

Links:

Rotel RC-1570:
 
STM32 CPU:
 
 
YMODEM:  
Real Time Web Analytics