Tag Archives: Script

Powershell: Limit API iterations in a single call

Problem:

Many APIs limit the number of iterations that you can make in a single API call. For example, Brightpearl limits you to getting information for a maximum of 200 orders in a single API call. If you place a call with more than 200 orders, it will simply return an error message. SmartyStreets also places a limit of 100 addresses that you can validate with a single API call.

Solution:

Dave Wyatt at PowerShell.org provides the following solution.

Lets assume there is an array of 1000 addresses which are returned by convertfrom-csv. Here are the first couple of records from the original .csv file.

PS>cat lapsed.csv
Addressee,first,spouse,Organization,Street,City,State,ZIP
Joe Dokes,Joe, Mary,,,601 W 57TH St Apt 361,New York,NY,10019
Mary Smith ,Mary,Howard,,347 Poor Farm Rd,Colchester,VT,05446
Lu-Anne Jorden,Lu-Anne,Jess,,9603 North Kiowa Rd.,Parker,CO,80138

Here is the command that we use to read in the list into the variable $bigLlist

$bigList =(cat lapsed.csv | convertfrom-csv | 
Select-Object Addressee, Organization, Street, City, State, Zip )

$bigList is a custom object with the following layout:

PS>$biglist | get-member
TypeName: Selected.System.Management.Automation.PSCustomObject
Name         MemberType    Definition 
----         ----------    ---------- 
Equals       Method        bool Equals(System.Object obj) 
GetHashCode  Method        int GetHashCode() 
GetType      Method        type GetType() 
ToString     Method        string ToString() 
Addressee    NoteProperty  System.String Addressee=Kamal Aboul-Hosn 
City         NoteProperty  System.String City=New York 
Organization NoteProperty  System.String Organization= 
State        NoteProperty  System.String State=NY 
Street       NoteProperty  System.String Street=601 W 57TH St Apt 361
ZIP          NoteProperty  System.String ZIP=10019

If you look at this in Powershell, it prints out the contents of each record.

Addressee    : Joe Dokes
Organization :
Street       : 109 Fern Ct.
City         : Delray Beach
State        : FL
ZIP          : 33444

Addressee    : Mary Smith
Organization :
Street       : 205 Dorado Dr
City         : Cherry Hill
State        : NJ
ZIP          : 08034

Addressee    : Lu-Anne Jorden
Organization :
Street       : PO Box 81666
City         : Fairbanks
State        : AK
ZIP          : 99708

Ok, so now we have the full list as an object. The list now needs to be subdivided into groups of 100.

$counter = @{ Value = 0 }
$groupSize = 100
$groups = $bigList | Group-Object -Property { [math]::Floor($counter.Value++ / $groupSize) }

The $counter variable is a hash table, initialized to zero.
The $groupsize variable is the size of the individual group that can be sent. In our example it is set to 100, for a maximum of 100 addresses to be sent at a time.
The $groups variable creates a custom object, with the following members:

PS>$groups | gm
   TypeName: Microsoft.PowerShell.Commands.GroupInfo

Name        MemberType Definition                                                      
----        ---------- ----------                                                      
Equals      Method     bool Equals(System.Object obj)                                  
GetHashCode Method     int GetHashCode()                                               
GetType     Method     type GetType()                                                  
ToString    Method     string ToString()                                               
Count       Property   int Count {get;}                                                
Group       Property   System.Collections.ObjectModel.Collection[psobject] Group {get;}
Name        Property   string Name {get;}                                              
Values      Property   System.Collections.ArrayList Values {get;}                      

If you print out the contents of $groups, you see the following list. (I’ve truncated for readability…)

PS>$groups
Count Name     Group                                                                                                              
----- ----     -----                                                                                                              
  100 0        {@{Addressee=Kamal Aboul-Hosn; Organization=; ...
  100 1        {@{Addressee=Chandler Dawson; Organization=; ...   
  100 2        {@{Addressee=Sidsel Heney; Organization=; ...
  100 3        {@{Addressee=John Marchetti; Organization=; ...
  100 4        {@{Addressee=Jane Ramsey; Organization=; ...
   59 5        {@{Addressee=James Tulloh; Organization=; ... 

This shows that I have 559 names in the original file which has been divided up into 5 groups of 100 and one of 59 names.

The next and final step is to iterate through each group and make the API call.

 
foreach ($group in $groups)
{
    $littleList = $group.Group | ConvertTo-Json
  
$Output = Invoke-RestMethod -Uri $Uri -Body $littlelist -ContentType application/json -Method Post 
}

The steps are:
For each group
Convert the addresses in one group to JSON
Assign it to the variable $littlelist
Send the contents of $littlelist as the body of the API call.
End Loop.

Debugging in PowerShell

The PowerShell integrated scripting environment (ISE) has many of the trappings of a full-fledged programming GUI, including a capability for debugging with breakpoints. There is a TechNet article on debugging from which this discussion is cribbed.  The ISE has a subset of the command-driven breakpoint capability, in that it only allows the setting of line breakpoints. In the command environment, you can also set variable breakpoints, which execute when the value of a variable changes, and command breakpoints, which execute when a certain command is reached.

Breakpoints can only be set for a script that has been saved.

In the ISE window a breakpoint can be set from the debug menu, (Toggle Breakpoint)  or by pressing F9 when the cursor is on the line that you want to use for the breakpoint.  Once set, the line will be highlighted.

After setting a least one breakpoint, you can run the single-stepper. This executes the script one line at time.

Step Into: Executes the current statement and stop at the next statement. If the statement is a function or script, it goes into the function or script and then stops.  F11

Step Over: Execute the current statement and stop at the next statement.  If the statement calls a function or script, it executes the function or script and then returns to the next statement in the original script. F10

Step Out: Executes the current function and then returns to the level above in the call stack. If there are statements remaining in the sub-function, those are executed before the return. Essentially this is something like “finish running this function, and return…”

Continue: Execute to the next breakpoint without single-stepping.

What I’ve been doing as I’ve been learning PowerShell is single stepping through a script, which allows me to look at the effect of a single statement before moving on to the next statement.  This involves setting a breakpoint a the top of the script, and then hitting F11 to toggle through the script.

Calling sub-scripts.

Scripts can be called from other scripts using the Invoke-Expression commandlet.  Example:

Invoke-Expression -Command ./PSFTPDEMO.ps1

If the subscript is located in the current working directory, or within the same directory as the main script, it needs to be prefaced with the ./ path as shown above.

The subscript inherits all variables from the main script unless those variables are declared private in the main script.

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

Rebootolator: Execute a Remote Linux Shell Script from Windows

Ok,  so, your mission, should you decide to accept it, is to restart mySQL and Apache on a remote server. This restarts a balky web site hosted by Apache, and also restarts a mySQL server which is used for a back-end for Drupal.

You want to execute this from your Windows computer.

The target computer runs CentOS 5.6 This is an (ancient) Red Hat Linux derivative, running (ancient) mySQL and Apache.

I ended up using PLink called from a Windows .CMD file to execute a bash shell script.  The shell script looks like this:

Rebootolator

#!/bin/bash -p
# Rebootolator – Reboots Apache and mySQL on a target Server
# LK Microdesign June 25, 2014
TERM=”xterm”
export TERM
clear
echo
echo ‘Rebooting Apache and mySQL on myServer’
echo ‘———————————–‘
echo ‘Restarting mySQL’
/etc/init.d/httpd restart
echo ”
echo ‘Restarting the Apache web server.’
/etc/init.d/mysqld restart
echo ‘Reboot procedure completed’


Note this script is not stored on the target server, but simply put in the same folder as the windows cmd file on my windows box.  

Now for the Windows command file: 

Reboot.CMD

:: Batch file to restart services on myServer
:: Restarts mySQL and httpd 
:: Uses the Rebootolator shell script
:: LK/Microdesign August 12, 2014  
@echo off
cls
echo. 
echo.
plink -ssh username@192.168.xxx.xxx -m rebootolator.sh -pw mypass
echo.
echo.

pause >nul | echo Press any key to exit. 

So, lets deconstruct the Windows Reboot.CMD file.
The first four lines are comment lines. Turns out, you can use two colons to preface a comment in Windows, (who knew?) instead of REM.
Line 5 turns off output to the screen.
Line 6 clears the screen.
Line 7 and 8 put in blank lines.
All the work happens on line 9, using the PLINK command. PLINK is the command line version of PUTTY, a free open source terminal program for Windows workstations. Both PLINK and PUTTY are pretty wonderful and highly recommended if you need to access Linux machines from Windows.
-ssh means “use the secure socket layer protocol to log into this machine”
username@192.168.xxx.xxx is a administrator’s account on the target machine,  probably the root account.
-m rebootolator.sh is the name of the shell script (above) that needs to run on the target machine.
-pw mypass is the password for the account used to log into the machine.

Deconstructing the Rebootolator.sh script:
#!/bin/bash -p  just means this is a BASH script
The two commands that actually restart the mySQL server, and the Apache server are: 
/etc/init.d/httpd restart
/etc/init.d/mysqld restart

The rest, (the echo commands) write out what  is happening at the command line. The Term command is my attempt to avoid a harmless error message that occurs when the script starts to execute.

Since I didn’t realize I could host the Rebootolator.sh script in my Windows folder, I originally though I’d have to log into one Linux box, and then execute the script on the target box.  Turned out the whole thing was simpler using PLINK, which is the equivalent of SSH and SSHPASS programs used to access remote machines from the Linux command line.