Modification in Remove-ScriptVariables by http://www.ehloworld.com/247

I tried to use the script created at Function: Remove-ScriptVariables – Cleaning Up Script Variables in PowerShell by Pat Richard

There seemed a issue which makes this script unusable. I then made some changes in it. Changes added are for removing ‘SCRIPT‘ from variable names and cleaning the variables in the defined scope of the script.


function Remove-ScriptVariables()
{
Param(
     [string]$path,
     [string]$scope
)
     $result = Get-Content $path |
        ForEach{ if ( $_ -match'(\$.*?)\s*=') {
            $matches[1]  | ? { $_ -notlike'*.*' -and$_ -notmatch'result' -and$_ -notmatch'env:'}
        }
     }
     ForEach($v in ($result | Sort-Object | Get-Unique)){
        Write-Host "Removing" $v.replace("$","")
        Remove-Variable -Name:($v.replace("$","").replace("SCRIPT:","")) `
            -Scope:Script -ErrorAction:SilentlyContinue
     }
} # end function Remove-ScriptVariables

Do ‘Get-Help Remove-variable -full | more’ to know what needs to be passed for Scope. Usually “SCRIPT” should be passed. This function can also be called at end of a function for better control with scope being defined as “LOCAL”. An example of using it as follows. This will remove script level variables created inside the script. Variables created inside a function will anyway be not accessible outside. ‘main’ is the function where I usually keep all my code.

try
{
    main
}finally{
    Remove-ScriptVariables -path:$MyInvocation.MyCommand.Name -scope:"SCRIPT"
}

Removing references of SongsPk.info from downloaded bollywood songs

If you are a software engineer from India, you must have downloaded Bollywood songs from Songspk.info or one of its clone sites at least once. Its a nice service for sure but they definitely have their own quirks. Checking the music file in Windows explorer or Media player will show songspk.info in multiple place including in file names and all the tags. They definitely deserve to do it given the service they provide but I intend to remove that information from downloaded files to keep them short and clean in my media players and hence decided to use Powershell for some automation. Result of that effort is as follows

Before using this, make sure to download taglib-sharp on some folder as it needs to be loaded. Before running any command, make sure to run it with -Whatif parameter to understand what it will do. Code is divided into 3 sections. I intend to add function for modifying tags with multiple values later on. I am greatly indebted to all bloggers on powershell and especially stackoverflow for helping me along the way. They are too many to list out here.


Function Check-TagLibLoad()
{

#validate if taglib-sharp is loaded or not
$taglibload = [System.AppDomain]::CurrentDomain.GetAssemblies() | `
Select-Object -Property FullName | `
Select-String -Pattern "taglib-sharp"
if (!$taglibload){
Throw "Load Taglib using [Reflection.assembly]::LoadFrom(<Full path of downloaded taglib-sharp dll like D:\temp\taglib-sharp-2.1.0.0-windows\Libraries\taglib-sharp.dll>)"
}
}

Function Rearrange-Patterns()
{
# Rearranges array so that if string A is part of B, A comes after B
Param(
[ValidateNotNullOrEmpty()]
[Parameter(Mandatory=$true)]
[String[]]$Patterns
)
[System.Collections.Generic.List[System.String]]$PatternsTemp = $Patterns | Sort-Object -Unique
for ($cnt1 = 1; $cnt1 -lt $PatternsTemp.Count; $cnt1++){
do{
$found = $false
for ($cnt2 = 0; $cnt2 -lt $cnt1; $cnt2++){
if ($PatternsTemp[$cnt1].Length -le $PatternsTemp[$cnt2].Length){
continue
}
if ($PatternsTemp[$cnt1] -match $PatternsTemp[$cnt2]){
$PatternsTemp.Insert($cnt2,$PatternsTemp[$cnt1])
$PatternsTemp.RemoveAt($cnt1+1)
$found = $true
break
}
}
}while($found -eq $true)
}
$PatternsTemp
}
# Rearrange-Patterns -Patterns "Songspk.info","songs","- Songspk.info","so","pk","info","Songspk","[Songs]"

This function uses above two functions. Save all three in one file and then dot source that file and use this function through pipe lining. Make sure to run with -WhatIf first and carefully examine output.

Function Update-Simple-tags()
{

# Update tags with simple non-array values
[CmdletBinding()]
Param(
[ValidateNotNullOrEmpty()]
[Parameter( Position=0, Mandatory=$true, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
[Alias('FullName')]
[String[]]$FilePath,
[ValidateNotNullOrEmpty()]
[Parameter(Mandatory=$true)]
[string[]]$RemovePatterns,
[switch]$WhatIf
)
begin{
Check-TagLibLoad
$RemovePatterns = Rearrange-Patterns -Patterns:$RemovePatterns
}
Process
{
Unblock-File -LiteralPath:$FilePath

$Music = [taglib.file]::create($FilePath)
$TagList = @("Title", "Comment", "Lyrics", "Conductor", "Copyright")
$Update = $False
$Message = @("$FilePath")

foreach ($tag in $taglist)

{
$OldTagVal = $Music.tag.$tag
$RemovePatterns | ?{$Music.tag.$tag -Match $_} |

%{
$Music.tag.$tag = ($Music.tag.$tag -replace $_, "").Trim()
$Update = $true
}
if ($update -eq $true) {
$Message += (" '$Tag': '$OldTagVal' to '"+$Music.tag.$tag+"'")}
else{
$Message += (" '$Tag': No Update")
}
$Update = !($Whatif)
}
if ($Update -eq $true) {
$Music.save()
}
$Message
}
End{
}
}

# dir -filter 2015* -Directory | %{dir -Path $_ -Filter *.mp3 -File} | Update-Simple-tags -RemovePatterns "Songspk.info","- Songspk.info","www.SongsPk.Info" -WhatIf  | Out-File Update.log
# dir -filter 2015* -Directory | %{dir -Path $_ -Filter *.mp3 -File} | Update-Simple-tags -RemovePatterns "Songspk.info","- Songspk.info","www.SongsPk.Info" | Out-File Update.log

Below are some commands that can be used to edit downloaded files before running above functions to ensure files are in good naming convention to be modified. Names with ‘[‘ in them are tough to handle otherwise. Unblocking is needed since files are downloaded from internet. Rename-Item cannot work with file with special characters hence Move-Item. Make sure to use -WhatIf beforehand with each command. There is a blog post that talks about unzipping zipped file from Powershell but you can discover that if needed.

#Dir -Filter 2015-*.zip | Unblock-File
#Dir -Filter 2016* -Directory | Move-Item -Destination {$_.FullName -replace "320kbps",""}
#Dir -Filter 2016* -Directory | Move-Item -Destination {$_.FullName -replace "\[Songspk.info\]",""}
#Dir -Filter *-2015.zip | Move-Item -Destination {"2015-"+($_.Name -replace "-2015","")}
#Dir -Filter 2016* -Directory | %{dir -Path $_ -recurse -File} | Move-Item -Destination {$_.FullName -replace "\[Songspk.info\] ",""}
#Dir -Filter *2016* -Directory | | Move-Item -Destination {$_.Name -replace "\[Songspk.info\] ",""}
#[Reflection.Assembly]::LoadFrom("D:\temp\taglib-sharp-2.1.0.0-windows\Libraries\taglib-sharp.dll")

Using Sendgrid with Powershell

Create a sendgrid account at https://sendgrid.com/

Download nuget.exe from https://www.nuget.org/nuget.exe and save it in some folder where sendgrid will be installed.

Run ‘nuget.exe install sendgrid’ on command line from the path where nuget.exe is saved. Two sendgrid folders will be created with structure like below in the same directory from where the command is run. No need to use Run as administrator option.

  • Sendgrid.6.1.0\lib\SendGridMail.dll
  • Sendgrid.6.1.0\Sendgrid.6.1.0.nupkg
  • SendGrid.SmtpApi.1.3.1\lib\net40\SendGrid.SmtpApi.dll
  • SendGrid.SmtpApi.1.3.1\lib\portable-net4+wp81\SendGrid.SmtpApi.dll
  • SendGrid.SmtpApi.1.3.1\SendGrid.SmtpApi.1.3.1.nupkg

These folders are downloaded by nuget from https://github.com/sendgrid/sendgrid-csharp which is official location for SendGrid C# libraries.

This install option will not add these assemblies to GAC so you will need to use either Add-Type or [Reflection.Assembly]::LoadFrom(…)  option to load these libraries in session or script. Overall Code would be like below

$SGMail= [Reflection.Assembly]::LoadFile("C:\Software\Sendgrid.6.1.0\lib\SendGridMail.dll")
$SGSMTP= [Reflection.Assembly]::LoadFile("C:\Software\SendGrid.SmtpApi.1.3.1\lib\net40\SendGrid.SmtpApi.dll")</code>

$myMessage = New-Object -TypeName:SendGrid.SendGridMessage
$myMessage.From = New-Object System.Net.Mail.MailAddress("user@example.com");
$recipients = @("Another user &lt;Anotheruser@AnotherDomain.com&gt;")
$myMessage.AddTo($recipients);
$myMessage.Subject = "Testing the SendGrid Library"

$myMessage.Html = "&lt;p&gt;Hello World!&lt;/p&gt;"
$myMessage.Text = "Hello World plain text!"

$username = "sendgridusername"
$password = "sendgriduserpassword"
$credentials = New-Object -TypeName:System.Net.NetworkCredential -ArgumentList:$username,$password

$TransportWeb = New-Object -TypeName:Sendgrid.web -ArgumentList:$credentials
$returnval = $TransportWeb.DeliverAsync($myMessage)
$returnval

Easiest way to figure out the exported classes from Sendgrid DLLs is to load these as reference in a VS 2015 VC# windows console app where you can then use Object browser to access all classes exported by these DLLs. Powershell has a convoluted way to show that but no point wasting time behind that when VS Community 2015 is free for all.

Definitely, this is not most secure code, but it works. Also, do remember that using this for internal organizational mails may be security risk since Sendgrid SMTP server would be transmitting it and thus they can have access to all your mails.

two Sendgrid classes used here are Sendgrid.sendgridmessage and Sendgrid.web. System.web is not getting used as that may seem look like from Sendgrid Github example.