Tag Archives: Script

Tech Friday: Debugging the WordPress White Screen of Death

motor-1381998_1280Problem: I attempted to change a password for a user of the WordPress web site. I got into the administrator’s dashboard, choose “Users”, found the person’s entry, changed their password, clicked on “save changes” and Poof! I get a blank screen.


It turns out there is a name for such screens, and the name is called the WordPress White Screen of Death, or WSOD.

There are a ton of possible causes for this, but many of them relate to a problem with PHP code located someplace  within WordPress, or within WordPress plugins. Since the WSOD is just that…it doesn’t show any kind of detailed error message, one approach to finding the problem is to enable error checking and display at the PHP level. This is a quick entry in the WordPress wp-config.php file located in the root WordPress directory.  Here’s the file as it shows up in FileZilla.


And here is the contents of the file as displayed in Notepad++


The trick is simply to change false to true to enable the display of error codes.  And sure enough,  once I did that and retried the password change operation I saw the following message:

Fatal error: Call to undefined function curl_init() in /var/www/html/wordpress/wp-content/plugins/gmail-smtp/class.phpmaileroauthgoogle.php on line 171

This was an indication that a plugin which I had added was causing the error. Once I removed the plugin, I could change my user’s password without problems and the WSOD was banished, at least for now.

File Management in Powershell

I’m looking to do the following in Powershell

1. Is a file that exists in a source folder more recent than a file in a target folder?
2. If it the file is more recent…copy it to the target folder, but before copying…
3. Back up the current version in the target folder, by appending a date to the file name.

Does a file exist?

test-path <filename>
This returns TRUE or FALSE if the file exists. If the file is in the current folder, then you can just list the file name, otherwise, the full path has to be included.

What is the file’s date and time?

The file date and time are properties of the file name, obtained via the Get-Item cmdlet.  We can assign these to a variable. Here I will compare file dates between two files that have the same name, but reside in different folders, one located along the default path, and one located on drive W.

$Sourcedate = (Get-Item w:myfile.csv).LastWriteTime
$TargetDate = (Get-Item myfile.csv).LastWriteTime
If ($Sourcedate = $Targetdate) {"True"}
If ($Sourcedate -lt $Targetdate) {"True"}
If ($Sourcedate -gt $Targetdate) {"True"}

Note (rather irritatingly….) that the usual comparison operators are different in Powershell.

=  -eq Equal
<> -ne Not Equal 
>= -ge Greater than or equal 
>  -gt Greater than
<  -lt Less than 
<= -le Less than or equal


Back up the target file

Having determined that the source file is newer than the target file, we now want to back up the target file, incorporating the date within the renamed filename.


Since we’ve used the functions for this in another post someplace,..

$ShortDate= $SourceDate | Get-Date -UFormat %Y%m%d

This returns the date in a short form:


Now append the date to the filename

Rename-Item myfile.csv $newfilename

This results in a file name of:


Now we can do the copy from the source folder to the target.

Copy-Item  w:myfile.csv





Powershell: Search and Replace in text files

Searching and replacing within Powershell, seems a little awkward.

To do a search and replace, use the –replace parameter of ForEach-Object, with two attributes, the first being the thing to search for and the second being the replacement.

Get-Content -path ./NGA_Tracking.csv | ForEach-Object {$_ -replace ‘Tracking’, ‘TrackNum’}

You can do a series of these in a single set of piped commands….

Get-Content -path ./NGA_Tracking.csv | ForEach-Object { $_ -replace ‘Tracking’, ‘TrackNum’ `
    -replace ‘X’, ‘Y’ `
    -replace ‘A’, ‘B’ } |
Set-Content $mynewfile

In the case of a text file, each object being modified in the For-Each loop is a string terminated by a newline.

The good news is that there is full support for regular expressions, so if you know how to deal with those, they can be incorporated within the -replace mechanism.

I guess I’m still looking for something a bit more friendly for casual use, Wouldn’t it be nice, for instance to have something like Get-Content $myfile -replace ‘X’,’Y’.   Well, we actually can do this:

(Get-Content ./NGA_Tracking -raw) -replace ‘Tracking’, ‘TrackNum’ | out-file ./NGA_Tracking -Encoding utf8 

If you don’t put the parentheses around Get-Content $filename -raw you generate an error. The parentheses read the entire file into memory as an object, which can then take the -replace parameter. The -Encoding parameter is there to make sure the characters are all read correctly in subsequent uses of the file. (took lots of experimentation and blood on the floor, but that it what worked.)

The effect is the same, when the file name is replaced.

$Myfile = ‘./NGA_Tracking.csv’
(Get-Content $MyFile)  -replace ‘Tracking’, ‘TrackNum’ | Out-File $MyFile -Encoding utf8

But, if you create an object then it works.

$Myfile = Get-Content ‘./NGA_Tracking.csv’
$Myfile -replace ‘Tracking, ‘Tracknum’ 

Text to HTML

As we start fiddling with text files, the question comes up regarding the creation of html files.  There is a Convertto-HTML commandlet, which, on the face of it looks pretty rudimentary. But this TechNet article explains how to enhance things using styles.

Brightpearl API: Add UPS Tracking Numbers

We have now been using our web store for about a month, and for the most part things have been going pretty smoothly. One issue has been sending orders to our warehouse, and we’ve got a pretty good Powershell script that creates a comma delimited text file (.csv) of order numbers and address information from queries to the Brightpearl API. This file is sent daily to the warehouse via FTP, and warehouse staff  import the orders into their UPS Worldship program.


The second half of this saga is to obtain the UPS Tracking number for each shipment. Once the shipment has been processed in UPS Worldship, a tracking number is generated and stored in the UPS Worldship record for that shipment. Worldship has an export function which will add the tracking number to a .csv file of order numbers and tracking numbers that we can use to update the order record in Brightpearl. The structure of this file, (which is completely customizable) is:

Order Number – In our case it is the Brightpearl sales order number
Tracking Number – from UPS. These look like “1Z 041 388 03 8331 4101”
Expected Delivery Date.
The .csv file looks like this. (UPS loves long field names).


The next step is to walk through the .csv file, find an order number, and update the custom field PCF_TRACKING in Brightpearl to contain the tracking number. Here is the Powershell call to update a single record:

PS>$BPOrders=Invoke-RestMethod `
 -Uri http://ws-use.brightpearl.com/public-api/myBPAccount/order-service/order/100541/custom-field `
 -Body $body `
 -Headers $headers `
 -Method Patch

There are a couple points of interest here. For the most part it is “standard” Powershell syntax for the Invoke-RestMethod.
1. We invoke this by assigning the results of the API call to $BPOrders
2. The call has several lines; the line continuation character is a accent aigu or back-tick.
3. Note that this query uses a $headers variable which includes the two validation properties for the Brightpearl query: , the name of the application and the security token for the application. These are stored as a hashtable.

brightpearl-app-ref myappreference
brightpearl-staff-token mystaff-tokenXYZ123

More on obtaining the authcode here.

4. The $body variable is also created as a hashtable, but then converted to JSON, and placed between square brackets. This variable contains three parameters, the operation that you are performing on the record, the field that you want to modify, and the value that you want to put in the field. The syntax below simply says, “Replace the contents of the /PCF_TRACKING field with the value of 12345”.

$body=($body | ConvertTo-JSON)

The result is:

"op": "replace",
"path": "/PCF_TRACKING",
"value": "12345"

5. The -Method parameter is a “Patch”. This allows you to replace the contents of a single field in a record rather than replace an entire record as happens when you use PUT.

6. Finally note in the Invoke-RestMethod call, the URI contains “custom-field”. This is a literal, it isn’t the name of your custom field. The name of the custom field is contained in the body.I In the example above, it is “/PCF_TRACKING”

The above API call will replace the contents of a single field in a single record. The next step is to be able to loop through the .csv file, and for each record, find the corresponding record within the Brightpearl database, and update its Tracking number field.

Oh, one more thing, the results of the operation are contained in $BPOrders. The API actually returns the contents of ALL custom fields. You can choose which ones you want to see using dot notation.


PowerShell: Simple GUI Message Boxes

One way to build simple message boxes in PowerShell is to “borrow” from .NET COM objects. Basically you initialize the object…(a.k.a. load the code for generating a messagebox), and then you create instances of the object which are the actual message boxes. These messagebox code may  be familiar to anyone who has programmed in vbScript, or any of the Microsoft programming languages such as Visual Basic or C#.  The boxes can look pretty good, even though the coding is a bit arcane.

To get started, initialize the messagebox object. You only need to do this once per session.

PS> $wshell=New-Object -comObject Wscript.Shell

Now you can make message boxes until the cows come home.

PS> $wshell.Popup(“Hi…This is a lovely messagebox”,0,”My Window Title”)


You can have multi-line boxes by including the newline (back-tick+’n’) to separate lines.

PS> $wshell.Popup(“Hi! A list of shipping addresses will appear in the next window.`n

If you need to edit the addresses then… `n

  1. Go back to BrightPearl`n
  2. Make the address changes.`n
  3. Run this program again.”,0,”Send To Warehouse”)


The Buttons

You can have a buttons which return an integer based on which button is pressed.

In PowerShell, the button combinations are designated by integers:

0: OK
1: OK, Cancel
2: Abort, Retry, Ignore
3: Yes, No, Cancel,
4: Yes, No,
5: Retry, Cancel

The parameters for showing a window are:

<messagetext>, <duration>, <window title>, <button integers>

PS> $wshell.Popup(“Hi…This is a lovely messagebox”,0,”My Window Title”,1)

The first parameter is the message that you want to appear in the box. This is a string.

The second parameter “duration”, is an integer that specifies how long you want the messagebox to stay open if there is no activity from the user. If you specify ‘0’, then the box stays open forever. Note that your script is completely paused when this is the case. If you use a positive integer, that is the length in seconds that the messagebox stays open.

The third parameter is a string that is the title of the box. This appears in the top of the window frame.

In the example above, the messagebox call specifies “1” for the OK and Cancel button combination. When the user clicks on a button the messagebox closes, and returns an integer, in this case, 1 for OK or 2 for Cancel. The integers are displayed on the PowerShell command line.  (Technically, the integers are returned to the pipeline).

Note that these returned integers are have nothing to do with the integer used to determine which buttons are displayed. (Why do I have to remind myself of this?) 

Button Return Values

OK Cancel Abort Retry Ignore Yes No
1 2 3 4 5 6 7

Instead of having the result go to the pipeline, you can store it in a variable for further use. Capture the result variable by assigning the message box to a variable.

 PS> $result=$wshell.Popup(“Hi…This is a lovely messagebox”,0,”My Window Title”,1)

PS> $result

The Icons

Messageboxes can also have an icon. There are four to choose from, and each has a designated integer.

Stop 16
Question 32
Exclamation 48
Information 64

Now, here’s the arcane part.  To display an icon,  you take the icon’s numeric value and add it to the numeric value of the button numeric value.  So, for example to place a Stop icon on our sample message box with OK and Cancel buttons  we add 16 to 1. Its not like they couldn’t provide another parameter?

PS> $result=$wshell.Popup(“Hi…This is a lovely messagebox”,0,”My Window Title”,65)


If you get an error message, when putting up a messagebox, like the one below…   it means that you didn’t run the New-Object cmdlet one time in your PowerShell session, prior to making a call to put up a messagebox.

PS> $wshell=New-Object -comObject Wscript.Shell

Having run that once, you can create as many messageboxes as you need within that particular PowerShell session.

You cannot call a method on a null-valued expression.
At line:1 char:1
+ $result=$wshell.Popup("Hi…This is a lovely messagebox",0,"My Window Title",65)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull


Powershell: Basic Address List Processing

One of the great things that was always a little bit fun (well, for some us… what passes for fun) is processing lists using Unix/Linux shell scripts and tools. When you are in practice, you can perform miracles; leap tall buildings in a single bound. Let’s see what we can do with a file using Powershell commands.

I received a file of “lapsed” donors. These are donors to our organization that gave to one of our campaigns in the past, but haven’t given recently. We know they were our friends in the past, and we think they still are, so we’d like to contact them for a one-time mailing, and/or add them to our master mailing lists.

The file is named “lapsed.csv”. The csv extension suggests this is a text file with a “comma separated values. And indeed, if I look at this file, at the powershell prompt, it is easily visible.

PS C:UsersLarrypowershell> cat lapsed.csv

This shows a comma delimited file with a header line:

Joe Blow, Joe,,,123 W 57TH St Apt 123,New York,NY,10019
Jill Smith,Jill,Howard Services,123 Poor Farm Rd,Colchester,VT,05446

Our standard is:

Org, fname, lname, address1, address2, city, state, zip

So, among other things, we’re going to want to change the order of the information in the fields, as well as the field names.

First thing to do is to import the file into a single PowerShell variable, and then see what we’ve got.

PS>$lapsed= Import-CSV lapsed.csv

Addressee : Joe Blow
 first : Joe
 spouse :
 Organization : Paul C Bunn Elementary
 Street : 123 W 57TH St Apt 123
 City : New York
 State : NY
 ZIP : 10019
Addressee : Jill Smith
 first : Jill
 spouse :
 Organization : Howard Services
 Street : 123 Poor Farm Rd
 City : Colchester
 State : VT
 ZIP : 05446

Using import-CSV, the file is converted into a series of custom objects with members that correspond to the existing field names …so further manipulations can be done using object manipulations, instead of just a bunch of searching and replacing. (Well that’s the theory anyway).

We can find out the number of records we have by looking at the count attribute.

And we can see the “members” or field names of each record by using Get-Member

PS>$Lapsed |Get-Member

TypeName: 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=Joe Blow
 City NoteProperty System.String City=New York
 first NoteProperty System.String first=Joe
 Organization NoteProperty System.String Organization=Paul C Bunn Elementary
 spouse NoteProperty System.String spouse=
 State NoteProperty System.String State=NY
 Street NoteProperty System.String Street=123 W 57TH St Apt 123
 ZIP NoteProperty System.String ZIP=10019

Ok…we knew the field names before by just looking at the raw .CSV file. But now we have seen how the Import-CSV command converts the .CSV file to an array of objects with a type of PSCustomObject.  Since each address record is an object, the way we manipulate it is to use object methods.

1. Add a lname field for the last name
PS>$lapsed | Add-Member -Name “lname”

That takes the $lapsed table and pipes it to the Add-Member cmdlet. This adds the the member to EACH object in the table, rather than adding it to the table itself.

2. Add a fname and lname fields for the first and last name
PS>$lapsed | Add-Member -Name “fname” -MemberType NoteProperty -Value “”

PS>$lapsed | Add-Member -Name “lname” -MemberType NoteProperty -Value “”

Now the fields look like this:
Addressee : Joe Blow
 first : Joe
 spouse :
 Organization : Paul C Bunn Elementary
 Street : 123 W 57TH St Apt 123
 City : New York
 State : NY
 ZIP :
 lname : ""
 fname : ""

3. Copy data from the first name and organization fields to their new fields.
PS>$lapsed | ForEach-Object ($_.fname) {$_.fname=$_.first}
PS>$lapsed | ForEach-Object ($_.org) {$_.org=$_.Organization}
This leaves us with a record looking like this.

Addressee : Joe Blow
 first : Joe
 spouse :
 Organization : Paul C Bunn Elementary
 Street : 123 W 57TH St Apt 123
 City : New York
 State : NY
 ZIP : 10019
 lname :
 fname : Joe
 org : Paul C Bunn Elementary

6. Having copied the data from the old fields to the new ones, we can delete the old fields.
There isn’t a cmdlet to remove an object member, so the you have to use a different nomenclature. (Note To Self… opportunity to make a custom cmdlet?)

PS> $lapsed | ForEach-Object ($_){$_.PsObject.Members.Remove(‘Organization’)}
PS>$lapsed | ForEach-Object ($_){$_.PsObject.Members.Remove(‘first’)}
PS>$lapsed | ForEach-Object ($_){$_.PsObject.Members.Remove(‘spouse’)}

Now a typical record is starting to look much more like what we want it to look like.

 Addressee : Joe Blow
 Street : 123 W 57TH St Apt 123
 City : New York
 State : NY
 ZIP : 10019
 lname :
 fname : Joe
 org : Paul C Bunn Elementary

7. We still need to pick out the last name from the Addressee field.
There might be a couple approaches to this using regular text search methods:
a. Given a string “Joe Blow”, we could find the first blank character, and then take anything to the right of if as our last name.
b. We could start at the right hand side and count backwards until we get to a space.
c. If there are word functions, we can choose the right-most word in the string.
d. Use the split function. This is what we’ll use.

PS> $lapsed | ForEach-Object ($_){$_.lname=$_.Addressee.split()[-1]}

8. Finally, we can eliminate the “Addressee” field
PS> $lapsed | ForEach-Object ($_){$_.PsObject.Members.Remove(‘Addressee’)}

Street : 123 W 57TH St Apt 123
 City : New York
 State : NY
 ZIP : 10019
 lname : Blow
 fname : Joe
 org : Paul C Bunn Elementary

9. Time to export back to a CSV file.
PS> $lapsed | Export-Csv -Confirm -Path “C:UsersLarryPowershellulapsed.csv” -NoTypeInformation

10. Almost done. The one frost is that the field order isn’t exactly as I’d like. This can be fixed with the Select-Object cmdlet.

PS > $lapsed | Select-Object -Property fname,lname,org,street,city,state,zip |
Export-CSV -Path “C:UsersLarryPowershellulapsed.csv” -NoTypeInformation

Recall when typing a string of commands with a pipeline, the pipe delimter will also act as a “newline”, so you can break the command up over the course of a couple of lines and have the full pipeline execute as one command.


As they say on public television: “Many thanks to the following:”

“jrv” on Microsoft Technet

“Root Loop” on StackOverflow

More Info:

More about the split function in Powershell help
PS> Get-Help about_Split

PowerShell Functions II – Output function results as a hash table

In a previous post I wrote a butt-simple function with three parameters, called it a couple ways, and talked about how the function returns its data either as a single string or as an array of variables. Before leaving this, I’m going to experiment about returning data as a hash table.

function Get-ReallySimple($fname,$lname,$age) {

return $OutTable


This prints out nicely, except it is in the wrong order.

 PS>Get-ReallySimple Joe Dokes 32

 Name                           Value
----                            -----
Age                            32
FirstName                      Joe
LastName                       Dokes

By adding the ordered keyword in front of the hash table definition, we can get the hash table to print in the order in which we asked for the function’s input paramenters.

function Get-ReallySimple($fname,$lname,$age) {

$OutTable= [ordered] @{"FirstName"=$fname;"LastName"=$lname;"Age"=$age}
return $OutTable


PS>Get-ReallySimple Joe Dokes 32

Name                           Value
—-                                —–
FirstName                     Joe
LastName                     Dokes
Age                               32

Since the result is a hash table we can also return a portion of the table using dot notation. We surround the functional call with parentheses to force the call to be evaluated first.

PS>(Get-ReallySimple Joe Dokes 32).FirstName


Of course instead of the the parentheses we probably should assign the call to a variable; and then dot notate that.

$Zilch=Get-ReallySimple Joe Dokes 32


There is  an Output Type attribute that can be applied to a function, but this appears to be cosmetic. It doesn’t enforce or do any error checking.  If your function returns a string, and Output type says “hashtable”, nothing happens; the function still return the string.  According to the help documentation the purpose of the Output Type attribute is to provide documentation; but when I queried with Get-Command Get-ReallySimple,  it returned nothing for the output.


Here is an updated version of my state abbreviation function, with changes prompted by Jeffery Hicks.
I’ve also added the Canadian provinces to the mix. The main change (apart from changing the name of the function to conform to the conventional Powershell verb-noun nomenclature), is to add the CmdletBinding section to specify a single parameter which needs to be supplied to run the function. The neat thing about this is that if you issue the command without the parameter it will automatically prompt for input.

function Get-StateAbbreviation {
# Takes upper, lower, or mixed case state name
# and return the two-letter abbreviation. 
# LK 3/17/15  rev. 3/26/15 per Jeffery Hicks 

# Still To Do: 
#   1. Full documentation 
#   2. Allow input from the pipeline 
#   3. Place in a module 

# Example calls: 
#   Get-StateAbbreviation Vermont     <-don't use parentheses
#   Get-StateAbbreviation -StateName Vermont
#   Get-StateAbbreviation "Vermont"
#   Get-StateAbbreviation $MyStateName 
# Note that this function has to appear before it is called in the code
# if it isn't part of a module. 

param (

Switch ($StateName.ToUpper()) {

($StateName="ALABAMA")        {$shortenState="AL"}
($StateName="ALASKA")         {$shortenState="AK"}
($StateName="ARIZONA")        {$shortenState="AZ"}
($StateName="ARKANSAS")       {$shortenState="AR"}
($StateName="CALIFORNIA")     {$shortenState="CA"}
($StateName="COLORADO")       {$shortenState="CO"}
($StateName="CONNECTICUT")    {$shortenState="CT"}
($StateName="DELAWARE")       {$shortenState="DE"}
($StateName="FLORIDA")        {$shortenState="FL"}
($StateName="GEORGIA")        {$shortenState="GA"}
($StateName="HAWAII")         {$shortenState="HI"}
($StateName="IDAHO")          {$shortenState="ID"}
($StateName="ILLINOIS")       {$shortenState="IL"}
($StateName="INDIANA")        {$shortenState="IN"}
($StateName="IOWA")           {$shortenState="IA"}
($StateName="KANSAS")         {$shortenState="KS"}
($StateName="KENTUCKY")       {$shortenState="KY"}
($StateName="LOUISIANA")      {$shortenState="LA"}
($StateName="MAINE")          {$shortenState="ME"}
($StateName="MARYLAND")       {$shortenState="MD"}
($StateName="MASSACHUSETTS")  {$shortenState="MA"}
($StateName="MICHIGAN")       {$shortenState="MI"}
($StateName="MINNESOTA")      {$shortenState="MN"}
($StateName="MISSISSIPPI")    {$shortenState="MS"}
($StateName="MISSOURI")       {$shortenState="MO"}
($StateName="MONTANA")        {$shortenState="MT"}
($StateName="NEBRASKA")       {$shortenState="NE"}
($StateName="NEVADA")         {$shortenState="NV"}
($StateName="NEW HAMPSHIRE")  {$shortenState="NH"}
($StateName="NEW JERSEY")     {$shortenState="NJ"}
($StateName="NEW MEXICO")     {$shortenState="NM"}
($StateName="NEW YORK")       {$shortenState="NY"}
($StateName="NORTH CAROLINA") {$shortenState="NC"}
($StateName="NORTH DAKOTA")   {$shortenState="ND"}
($StateName="OHIO")           {$shortenState="OH"}
($StateName="OKLAHOMA")       {$shortenState="OK"}
($StateName="OREGON")         {$shortenState="OR"}
($StateName="PENNSYLVANIA")   {$shortenState="PA"}
($StateName="RHODE ISLAND")     {$shortenState="RI"}
($StateName="SOUTH CAROLINA")   {$shortenState="SC"}
($StateName="SOUTH DAKOTA")     {$shortenState="SD"}
($StateName="TENNESSEE")        {$shortenState="TN"}
($StateName="TEXAS")            {$shortenState="TX"}
($StateName="UTAH")             {$shortenState="UT"}
($StateName="VERMONT")          {$shortenState="VT"}
($StateName="VIRGINIA")         {$shortenState="VA"}
($StateName="WASHINGTON")       {$shortenState="WA"}
($StateName="WEST VIRGINIA")    {$shortenState="WV"}
($StateName="WISCONSIN")        {$shortenState="WI"}
($StateName="WYOMING")          {$shortenState="WY"}
($StateName="WASHINGTON DC")    {$shortenState="DC"}
($StateName="ALBERTA")               {$shortenState="AB"}
($StateName="BRITISH COLUMBIA")      {$shortenState="BC"}
($StateName="MANITOBA")              {$shortenState="MB"}
($StateName="NEW BRUNSWICK")         {$shortenState="NB"}
($StateName="NEWFOUNDLAND")          {$shortenState="NL"}
($StateName="LABRADOR")              {$shortenState="NL"}
($StateName="NORTHWEST TERRITORIES") {$shortenState="NT"}
($StateName="NOVA SCOTIA")           {$shortenState="NS"}
($StateName="NUNAVUT")               {$shortenState="NU"}
($StateName="ONTARIO")               {$shortenState="ON"}
($StateName="PRINCE EDWARD ISLAND")  {$shortenState="PE"}
($StateName="QUEBEC")                {$shortenState="QC"}
($StateName="SASKATCHEWAN")          {$shortenState="SK"}
($StateName="YUKON")                 {$shortenState="YT"}

Default {$shortenState="XX"}

} # Switch 

return $shortenState

} # Function

Create U.S. State Abbreviations from State Names

function shortenState([string]$longName) {
# LK 3/17/15
# Takes upper, lower, or mixed case state name
# and returns the two-letter abbreviation.
# Example call:
#   shortenstate Vermont     <-don't use parentheses
#   "Vermont" | shortenState <- sent via a pipe
# Note that this function has to appear *before* it is called in a Powershell script.
Switch ($LongName.ToUpper()) {

  ($LongName="ALABAMA")        {$shortenState="AL"}
  ($LongName="ALASKA")         {$shortenState="AK"}
  ($LongName="ARIZONA")        {$shortenState="AZ"}
  ($LongName="ARKANSAS")       {$shortenState="AR"}
  ($LongName="CALIFORNIA")     {$shortenState="CA"}
  ($LongName="COLORADO")       {$shortenState="CO"}
  ($LongName="CONNECTICUT")    {$shortenState="CT"}
  ($LongName="DELAWARE")       {$shortenState="DE"}
  ($LongName="FLORIDA")        {$shortenState="FL"}
  ($LongName="GEORGIA")        {$shortenState="GA"}
  ($LongName="HAWAII")         {$shortenState="HI"}
  ($LongName="IDAHO")          {$shortenState="ID"}
  ($LongName="ILLINOIS")       {$shortenState="IL"}
  ($LongName="INDIANA")        {$shortenState="IN"}
  ($LongName="IOWA")           {$shortenState="IA"}
  ($LongName="KANSAS")         {$shortenState="KS"}
  ($LongName="KENTUCKY")       {$shortenState="KY"}
  ($LongName="LOUISIANA")      {$shortenState="LA"}
  ($LongName="MAINE")          {$shortenState="ME"}
  ($LongName="MARYLAND")       {$shortenState="MD"}
  ($LongName="MASSACHUSETTS")  {$shortenState="MA"}
  ($LongName="MICHIGAN")       {$shortenState="MI"}
  ($LongName="MINNESOTA")      {$shortenState="MN"}
  ($LongName="MISSISSIPPI")    {$shortenState="MS"}
  ($LongName="MISSOURI")       {$shortenState="MO"}
  ($LongName="MONTANA")        {$shortenState="MT"}
  ($LongName="NEBRASKA")       {$shortenState="NE"}
  ($LongName="NEVADA")         {$shortenState="NV"}
  ($LongName="NEW HAMPSHIRE")  {$shortenState="NH"}
  ($LongName="NEW JERSEY")     {$shortenState="NJ"}
  ($LongName="NEW MEXICO")     {$shortenState="NM"}
  ($LongName="NEW YORK")       {$shortenState="NY"}
  ($LongName="NORTH CAROLINA") {$shortenState="NC"}
  ($LongName="NORTH DAKOTA")   {$shortenState="ND"}
  ($LongName="OHIO")           {$shortenState="OH"}
  ($LongName="OKLAHOMA")       {$shortenState="OK"}
  ($LongName="OREGON")         {$shortenState="OR"}
  ($LongName="PENNSYLVANIA")   {$shortenState="PA"}
  ($LongName="RHODE ISLAND")   {$shortenState="RI"}
  ($LongName="SOUTH CAROLINA") {$shortenState="SC"}
  ($LongName="SOUTH DAKOTA")   {$shortenState="SD"}
  ($LongName="TENNESSEE")      {$shortenState="TN"}
  ($LongName="TEXAS")          {$shortenState="TX"}
  ($LongName="UTAH")           {$shortenState="UT"}
  ($LongName="VERMONT")        {$shortenState="VT"}
  ($LongName="VIRGINIA")       {$shortenState="VA"}
  ($LongName="WASHINGTON")     {$shortenState="WA"}
  ($LongName="WEST VIRGINIA")  {$shortenState="WV"}
  ($LongName="WISCONSIN")      {$shortenState="WI"}
  ($LongName="WYOMING")        {$shortenState="WY"}
Default {$shortenState="XX"}
  } #switch

return $shortenState

} # function shortenState

# The following lines import a .csv file, and modify the state field
# to the two-letter abbreviation 

$Deliveries=Import-Csv "c:userslarrypowershellworldship.csv"

$Deliveries | Foreach-Object ($_) {

  if ($_.State.length -gt 2) {$_.State = shortenState($_.State)}


Manage Linux Log Files

We were looking at log files in our various servers, with the idea that we could delete them to reclaim some disk space, but if they are properly set up with the logrotate command, they will be kept to a manageable size automatically. 

Log files live in /var/logs. There may be subdirectories within /var/logs for specific applications such as mySQL. 
Log files generally are managed through the logrotate command.  This is the program which deletes old logs, and stores and renames older versions of logs based on specifications that you put in to the logrotate.conf file.  The logrotate.conf file is typically located in /etc. It can contain defaults for all logs, and specifics for particular log files.  BUT….. 
Ugh.  Although the default specs for logs is the logrotate.conf file, some programs store their parameters elsewhere.  These include programs like apache, linuxconf, samba, cron, and syslog. 
The include parameters will read the contents of these other log parameter files, and include them in the logrotate.conf.  
(Note…these are the log configuration files,  not the log files themselves, which still appear in /var/log 
cat /etc/logrotate.d/httpd
/var/log/httpd/*log {
        /sbin/service httpd reload > /dev/null 2>/dev/null || true
The upshot is that most log files in /var/log will either be the current active log file for an application, or an archived version.  If the archives are compressed, then the suffix for the file will be .gz  

Reading the logs for user log-ins.  

Log files for logins, which contain the user name, time of access, and from where, are contained in two log files,  wtmp, and btmp.  On some systems there is also a utmp file. 
These are binary files, so that when accessed using cat, they will show gibberish. 
However, the last command will format them correctly.  
lastb shows the failed login attempts  (from wtmp)  – BSD
last shows successful login attempts.  (from btmp)  – BSD 
lastlog on Red Hat machines will also read the logins file. According to Wiki, this is “similar to last and lastb”, but last parses a different database (wtmp and btmp). 
tail -n30  shows the last 30 lines of a log file. 
tail  by default shows the last 10 
cat /proc/version  shows the version of linux 
df -h shows the installed hard disk(s) and their useage. 
cat /etc/passwd shows all of the user accounts. 
more, less for paging.  (less allows for paging backwards)