Tag Archives: Powershell

Powershell: Basic text processing

Problem:  I’ve received two files of eMail addresses. These represent one group that were awarded a grant, and much larger group that were rejected. I’m going to call these two files winners.txt and losers.txt.

I want to end up with the following:
1. Eliminate invalid eMail addresses
2. Eliminate duplicate records in both files
3. Check to see that anyone in the winners file does not appear in the losers file.

Although I’ve received these as an Excel Spreadsheet, I’ll use Excel to write them out as comma-delimited text files. Maybe later I’ll figure out how to work with the Excel spreadsheet directly from Powershell.

After exporting the eMail addresses from Excel they are contained in two .csv files….comma delimited text with each field enclosed in quotes. There were a huge number of blank lines at the bottom of each file, which I’m assuming are a result of the Excel export.

Working with the winners.txt file:

1. Count the number of lines in the file:
Get-Content winners.txt | measure-object -Line

2. Eliminate the blank lines. These were lines that had an empty string enclosed in double-quotes followed by a carriage-return, line feed..
 (Get-Content winners.txt -Raw)`
.Replace( "`"`"`r`n" ,"" )| Set-Content winners.txt

3. Eliminate the rest of the quotes
 (Get-Content winners.txt -Raw).Replace( "`"" , "" ) `
| Set-Content winners.txt

4. Validate for the presence of an @ character in each line. (Ok, I know there are some more robust email format evaluation routines using regular expressions or even .NET objects, but I’m reserving those for another time. Right now, I’m assuming that if a line includes an at sign ‘@’ then I can work with it).

(Get-Content winners.txt) | select-string "@" `
| Set-Content winners.txt

5. Eliminate duplicate lines
$fn=winners.txt
( Get-Content $fn ) | sort | get-unique >$fn

Note that you have to sort the lines to be able to get-unique.

Having done the above four steps on the winners’ file, I repeated them with the losers’ file. Then I compared the two files to find lines that appeared in both files, (which of course meant that my winners’ eMail addresses were present in the loosers’ file.)

5. Find lines that appear in both files.
Compare-Object -DifferenceObject $winners `
-ReferenceObject $loosers `
-ExcludeDifferent 

It turns out that all of my winners eMail addresses appeared in the loosers file as well. I deleted these with a manual search and replace… (but that’s another PowerShell story to look up).

Notes:
1. The parentheses around Get-Content in a command act like they do when doing arithmetic. They instruct PS to execute those commands first. This is necessary when modifying the conents  of a file without creating an intermediary file to hold the contents.  The downside is that the file is read entirely into memory, so there may be implications with especially large files.

2. The line continuation character is a back-tick character, “`”.  It also serves as the escape character when you need to include a particular character as part of a search string. So, in the search string in step 1,Replace( “`”`”`r`n” ,”” ) means, replace any line that has “” as its contents.

3. Find the default printer
Get-WmiObject `
-Query " SELECT * FROM Win32_Printer WHERE Default= $true"

From <https://wordpress.com/post/78494701/4&gt;

PowerShell: Shorten URLs with Google’s API

The following PowerShell code will return a shortened URL from a long URL using the Google link shortening URL API. Contrast this code with the code for Bit.ly. There are couple differences: 
1. Calling the Google API is done with a POST. With Bit.ly it is a GET. 
2. I’ve included an interactive prompt in the code below, that will get the long URL from the command line. Once the shortened link is printed, you can paste it to the clipboard. (Or…better yet, avoid mousing around, and pipe the result to the clipboard using the clip.exe utility 


PS >$MyShortURL.id | clip.exe 

3. If it doesn’t matter, and you are already using the Google API,  use Bitly; initial setup is a snap.  I worked out the Google version because we want to be able to track our shortened links using Google Analytics.  Links shortened by Google are automatically made into tracking links. 

4. The Google call uses the PowerShell commandlet Invoke-RestMethod. The Bitly call uses the Invoke-WebRequest commandlet.  

5. For troubleshooting, I used the HttpRequestor FoxFire plugin o make sure I was making the correct API call.  


# Generate shortened URL using the Google API 
# First time set up:  
# * Log in with your Google login name and password  
# * Go to the Google Developer Console at:
# * https://console.developers.google.com/project
# * Create a new project. 
# * Obtain an application key.(Don’t worry about oAuth)
# * Be sure that you allow requests from 
# * “all IP addresses” 

$APIKey=”xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx”

# Hard coded long link below,or comment out line 17 and 
# uncomment 20-23 for an interactive command line 

#######################################################
# Paste in the URL that you want to shorten here. 
 $LongURL=”http://twitter.com” 
#
#######################################################
# $Instructions = “You can paste a long URL into the`
# command line by right-clicking the mouse.`n”
# $Instructions 
# $LongURL= Read-Host “Enter or Paste in the Long URL”
#######################################################

#Convert the Long URL to a JSON key/value 
$LongHash=@{“longUrl”=$LongURL}
$MyLongURI = $LongHash | ConvertTo-Json

# Make the API call
$MyShortURL=Invoke-RestMethod `
-Uri https://www.googleapis.com/urlshortener/v1/url?key=$APIKey `
-Body $MyLongURI `
-ContentType application/json `
-Method Post

# Print out the shortened URL 
$LongURL
$MyShortURL.id

PowerShell FTP Follow-up

This script is an attempt to automate a lengthy error-prone copying and configuration process that we do each week. If we do the process manually it can take anywhere from five to twenty minutes, and it tends to have various points of failure.  The piece below is actually just one portion of the process. The steps include: 

1. Get the name of a new folder to be created on the server
2. Get the name of the file to be copied into the new folder
3. Using the two new names, build a text file which contains commands that will be fed into PSFTP
4. Call PSFTP and run the commands in the text file.

This  PowerShell script uses Putty FTP to log into an FTP server, create a new folder, and copy a file to that folder from the local host. Note the the steps for making the folder and copying the file are contained in a Putty script called gwkprocess.scr. This secondary script is is used as input to the Putty program after Putty makes the connection.  Those steps are typical FTP steps: 

CD / topdirectory
MKDIR  /new directory
CD /newdirectory 
PUT myfile.png  


<# Powershell Scripted FTP
LK 10.30.2014 
Send a file to the eMail server via FTP.
Uses the Putty Secure FTP program PSFTP
#>


# $FTPFolder=’/home/web/html/store/images/fy2014/Kids-Shop’
# Note that the login credentials are in clear text! 

# Enter the new folder name here. 
$NewFolder = “20141101ks”

# The Picture file to be copied is located in 
# C:UsersLarryPowershell 
# and should be named, with the usual naming convention
$PicFile = “20141101ks-image.png”

#Note line wraps. 

#Build the Putty Script file 
“cd /home/web/html/store/images/fy2014/Kids-Shop”| Out-File -FilePath C:UsersLarryPowershellgwkprocess.scr -Encoding ascii

“mkdir $Newfolder” | Out-File -FilePath  C:UsersLarryPowershellgwkprocess.scr  -Encoding ascii -Append


“put $PicFile” | Out-File -FilePath  C:UsersLarryPowershellgwkprocess.scr  -Encoding ascii -Append

“ls” | Out-File -FilePath C:UsersLarryPowershellgwkprocess.scr  -Encoding ascii -Append


# Call the putty program 
.psftp myuser@192.168.214.103 -P 22 -pw mypassword -v -2 -b gwkprocess.scr

This starts PSFTP in the Powershell window, makes the connection and then executes the gwkprocess.scr  steps. It then closes the connection. If there is a problem, PSFTP will print a failure message, but clearly there is room for more error checking on the front end. 

The presumption is that the secondary script gets rebuilt with new file and folder names each time the script is run. Obviously, there are some refinements to be included, like  interactive data entry of the file and folder names.

PowerShell: Shorten Links with the Bit.ly API

Isn’t it annoying….you have actually go to a web site to shorten your URL!  Here’s how to do it in PowerShell, and you’ll get the shortened URL printed on the command line.

If you save this script in a folder, you can run it by navigating to the script, right-clicking and choosing “Run in PowerShell”.

# Generate shortened URL using the Bitly API 
# To set this up: 
# * You must create an account at Bit.ly, and obtain an $ 
# * authorization token. 
# * Verify your Bit.ly account with an eMail that Bitly 
# * sends to your account. 
# * Obtain an authorization token at: https://bitly.com/a/oauth_apps
# Paste the authorization token here…

$OAuthToken=”xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx”

$Instructions = “You can paste a long URL into the command line by` right-clicking the mouse.`n”
$Instructions 
$LongURL= Read-Host “Enter or Paste in the Long URL”

# Make the call
$MyURL=Invoke-WebRequest `
-Uri https://api-ssl.bitly.com/v3/shorten `
-Body @{access_token=$OAuthToken;longURL=$LongURL} `
-Method Get

#Get the elements from the returned JSON 

$MyURLjson = $MyURL.Content | convertfrom-json 

# Print out the shortened URL 
$MyURLjson.data.url 

Pause

Powershell: Scripting FTP

Having spent some hours figuring out how to script an FTP transfer, I thought I’d describe my kludge. Maybe someone can suggest a more elegant way.  I’m trying to I’m connect to a FTP server on my Linux box to upload a file.
There are at least three approaches that can be taken:
1. Directly interact with .NET objects
2. Import a Powershell module for FTP
3. Use Powershell to manipulate a command line FTP program, such as the Putty Secure FTP program PSFTP.
I started with the second option recommended on TechNet. Looks great, and I thought that it was semi-official (being from Technet). I was unable to get a connection and I think it may be related to the fact that module apparently doesn’t support SFTP version 2.  There are a couple other quirks with the module… including the fact that the user name and password are passed to the command line as an object.  
By the way, both option 2 and 3 have the same name, PSFTP. 
Option 2 = Powershell FTP 
Option 3 = Putty Secure FTP 
So, I’m on to option 3.  This looks a little more promising.  One gotcha, however, is that calling Putty PSFTP from the Powershell ise, makes the connection but doesn’t return to show the PSFTP prompt. Here’s the command (so far) 
PS> .psftp myaccount@192.168.224.184 -p 22 -pw mypassword -v -2
This command shows that:
The psftp program is located in the current directory.
myaccount@192.168.224.184 – is the login account used for logging into the target machine
192.168.224.185 – is the IP address of the target machine
-p 22 – is port 22, used for Secure FTP
-pw is the password
-v is verbose (upon execution it returns all the steps of the login
-2 is SSL version 2.
Running this from the command line in the ISE gives the following:
  .psftp : Looking up host “192.168.214.184”
At line:1 char:1
+ .psftp myaccount@192.168.224.184 -P 22 -pw mypassword -v -2
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (Looking up host “192.168.224.184”:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError
Connecting to 192.168.224.184 port 22
We claim version: SSH-2.0-PuTTY_Release_0.63
Server version: SSH-2.0-OpenSSH_3.8.1p1
Using SSH protocol version 2
Doing Diffie-Hellman group exchange
Doing Diffie-Hellman key exchange with hash SHA-1
Host key fingerprint is:
ssh-rsa 1024 ce:ec:0d:c2:90:ab:5e:87:12:bf:ba:f9:78:77:89:fb
Initialised AES-256 SDCTR client->server encryption
Initialised HMAC-SHA1 client->server MAC algorithm
Initialised AES-256 SDCTR server->client encryption
Initialised HMAC-SHA1 server->client MAC algorithm
Using username “myaccount”.
Attempting keyboard-interactive authentication
Access granted
Opening session as main channel
Opened main channel
Started a shell/command
Connected to 192.168.214.103
Remote working directory is /ftproot
PS >
If you run this from the ise, it returns the PS command as shown.  
If you run this from a regular powershell command session, it will keep you in the PSFTP session, and you can run use the usual FTP commands….like CD, etc. 
In either case, the way Putty FTP can execute scripted commands is that the script has to live in a separate batch file that is called from the command line.  There doesn’t appear to be a  way to pass commands from Powershell to a running Putty SFTP session.  (hmm.. really?) 
Additioanal points: 
1. I might be able to configure the FTP server running on the Linux box to accept the connection from the PowerShell FTP module. I haven’t investigated that possibility but presumably it would be less secure in terms of encryption.

2. The script above has the name and password in clear text.  Not a best practice. 
3. Various versions of FTP are described on this page.  

BrightPearl API Part V – PowerShell

PowerShell, is a Microsoft download, currently at version 4.0.  It is a batch command language and enhanced command shell which is the current successor to the CMD.exe found in Windows. It seems to be a bit of a mash-up between the old DOS command line, the Unix-style shells like BASH, and includes connections to .NET objects. Unfortunately, it also abstracts a number of parameters to objects, such that you can’t just put stuff on a command line; you have to assign it to an object parameter when passing parameters, or when getting things out from a returned object. 
 
To continue with our Brightpearl example:
Recall that when working with the Brighpearl API, you have to first obtain a temporary authorization code, which is good for roughly 30 minutes. You do this by making an HTTP POST which includes your credentials in the body of the post.
 
Obtain a Brightpearl Authorization Code:
 
This is a two step process:
 
1. First stuff the authorization credentials into a variable. Note that the credentials are formatted in nested JSON notation.
$bpauth = “{apiAccountCredtentials:{emailAddress:”myemail@mycompany.com”, password:”Mypassword”}}”
2. Execute the command line call using the stored log-in credentials in the Body parameter
http://ws-use.brightpearl.com/mybpaccountname/authorise -Body $bpauth -ContentType application/json -Method Post
The Brightpearl server returns an authorization code which is displayed as an object with a series of parameters. The authorization code is contained in the a JSON string in the “Content” parameter.  This is the authorization code that must accompany any subsequent call to the Brightpearl API.
StatusCode        : 200
StatusDescription : OK
Content           : {“response”:”53145c429-x1xx-y2sf-z34a-8abc9cde96f9gh”}
RawContent        : HTTP/1.1 200 OK
                    Pragma: no-cache
                    ruid: a745efb3-2414-428f-8427-5001e3c810b8
                    Connection: keep-alive
                    Content-Length: 51
                    Cache-Control: no-cache, must-revalidate
                    Content-Type: application/json;char…
Forms             : {}
Headers           : {[Pragma, no-cache], [ruid, a745efb3-2414-428f-8427-5001e3c810b8], [Connection, keep-alive], [Content-Length, 51]…}
Images            : {}
InputFields       : {}
Links             : {}
ParsedHtml        : mshtml.HTMLDocumentClass
RawContentLength  : 51
To isolate the code itself, you have to assign the output of the above command to a variable, and then access it using dot notation.
So, restate the above command to assign the output to a variable:
$bpcode = Invoke-WebRequest -Uri http://ws-use.brightpearl/microdesign/authorize -Body $bpauth -ContentType application/json – Method Post
If you then execute $bpcode.Content, then you’ll get the authorization code, (again in JSON format).
PS C:UsersLarryPowerShell>$bpcode.Content
This returns:
  {“response”:”53145c429-x1xx-y2sf-z34a-8abc9cde96f9gh”}
To see this in a more readable format:
PS C:UsersLarryPowerShell>$bpcode.Content | ConvertFrom-Json
response
——–
53145c429-x1xx-y2sf-z34a-8abc9cde96f9gh
To assign the authorization code to a variable itself, we either have to strip it from the JSON code, or from the returned converted version.  It probably is easier to convert via the JSON code because we can do a text search everything after the colon, and then strip off the double quotes and the last curly bracket.
$bpstring=$bpcode.content
The following command strips off everything up to the start of the actual code.
 
$bpstring = $bpstring. Trimstart( “{`”response`”`:” )
It gives us:   
“53145c429-x1xx-y2sf-z34a-8abc9cde96f9gh”}
The following command strips off the final quote and curly bracket.
$bpstring = $bpstring. Trimend( “`”`}”)
This gives us our final result; what we’re really looking for:
53145c429-x1xx-y2sf-z34a-8abc9cde96f9gh

Final Script:

The final script is pretty close to the interactive commands entered at the PowerShell command line. The main exception is the addition of the back tick escape character within the script. If you use the PowerShell Interactive Shell as an editor,  it will color code things nicely and flag scripting errors. 
# BrightPearl API: Get an authorization code for subsequent API queries
# Note escape character is the “`” (back tick), instead of the usual backslash.
# Double quotes need to be escaped when nested inside.
# LK 10/9/2014
 
 
# Assign credentials to an authorization object.
$bpauth = “{apiAccountCredentials:{emailAddress:`”myeMailAddress@mycompany.com`”,password:`”myPassword`”}}”
 
# Execute the HTTP POST to retrieve the authorization code. The result is assigned to the string $bpstring
# Note use of the back tick as a line continuation character
$bpstring = Invoke-WebRequest `
-Body $bpauth `
-ContentType application/json `
-Method Post
 
$bpAuthCode =$bpstring . Content
$bpAuthCode =$bpAuthCode . Trimstart( “{`”response`”`:” )
$bpAuthCode =$bpAuthCode . TrimEnd( “`”`}” #Note escape codes for the search expression
 
# Print the Authorization Code
$bpAuthCode