I have no idea what I'm doing.

Wednesday, November 27, 2013

TRUE PowerShell command history persistence (i.e. Bash up arrow), surviving multiple sessions, syncing across multiple PCs, and a table full of fiiixins

A day of celebration is at hand.  For centuries Windows administrators have been living crippled and hellish existences.  Laughed at by some, mocked by others, and ignored by the rest.  All throughout the 19th and 20th century (as well as the entire 5th Age of Paladine), the command line history of each PowerShell session was eradicated upon exit.  Vaporized - trashed - hit over the head, tossed into a pickup truck, taken to an abandoned forest just off the highway, tossed into a pit, and burned till nothing was left but the smokey tears of sysadmins all across the world.

Sure, PowerShell had that 'hash tag + hit TAB' crap, but they've never had 'up arrow' access to the command history.  Well, not anymore...

To get started, you'll need three things:
  1. A script to backup and restore your command history each time you start/exit a PowerShell instance.  (don't worry, the execution time is negligible)
  2. This backup/restore script will require the PSReadLine module.
  3. The easiest way to get the PSReadLine module is to install PsGet.

Let's do this in reverse...

Step 1:  Install PsGet here: http://psget.net/.  For the security conscious people, alternate methods of installation are available, OR you take the security-lite approach and download/inspect the files before execution.
(new-object Net.WebClient).DownloadString("http://psget.net/GetPsGet.ps1") | iex

Step 2:  Install/Import the PSReadLine module.
install-module PSReadline

Step 3:  Add a script to your profile that loads/saves your command history.  Be sure to have the path ready (HistoryDirPath).  For me, I like to put his into a dropbox location and share it amongst my other workstations.  Or if you want to have some level of separation, change the file name (HistoryFileName)
$MaximumHistoryCount = 31KB
$ImportedHistoryCount = 0
$HistoryDirPath = "c:\dropbox\powershell\history\"
$HistoryFileName = "history.clixml"
 
if (!(Test-Path $HistoryDirPath -PathType Container))
    {   New-Item $HistoryDirPath -ItemType Directory }
 
Register-EngineEvent PowerShell.Exiting –Action {           
        $TotalHistoryCount = 0
        Get-History | ? {$TotalHistoryCount++;$true}
        $RecentHistoryCount = $TotalHistoryCount - $ImportedHistoryCount
        $RecentHistory = Get-History -Count $RecentHistoryCount 
        if (!(Test-path ($HistoryDirPath + $HistoryFileName)))
        {   
            Get-History | Export-Clixml ($HistoryDirPath + $HistoryFileName)
        }else
        {
            $OldHistory = Import-Clixml ($HistoryDirPath + $HistoryFileName) 
            $NewHistory = @($OldHistory + $RecentHistory)
            $NewHistory | Export-Clixml ($HistoryDirPath + $HistoryFileName)
        }
    }
 
if (Test-path ($HistoryDirPath + $HistoryFileName))
    {   
        Import-Clixml ($HistoryDirPath + $HistoryFileName) | ? {$count++;$true} |Add-History 
     Write-Host -Fore Green "`nLoaded $count history item(s).`n"
     $ImportedHistoryCount = $count
    }

# Importing PSReadline must come AFTER you load your command history
if ($host.Name -eq 'ConsoleHost')
    {
        Import-Module PSReadline
    }

# if you don't already have this configured...
Set-PSReadlineKeyHandler -Key UpArrow -Function HistorySearchBackward
Set-PSReadlineKeyHandler -Key DownArrow -Function HistorySearchForward 

Your profile location will be something like:
C:\Users\username\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1 

Now for the fiiixins...

Redirect your default profile to your tricked-out profile.
http://orsontyrell.blogspot.com/2013/11/saurons-powershell-profile-in-3-easy.html

Since you're putting your command history and profile on dropbox, don't forget to add your modules as well!

Setup a command line installer like Scoop or Chocolatey.
https://github.com/lukesampson/scoop/
http://chocolatey.org/

With one of these installer you're one line away from all sorts of cool tools, stuff like:  7zip, curl, grep, nano, git, openssh, vim, wget.  With Chocolately you can install goodies like Notepad++, Chrome, VLC, etc.


bunch of sources:
http://psget.net/
https://github.com/lzybkr/PSReadLine
http://stackoverflow.com/questions/17862618/loading-powershell-history
http://blog.clintarmstrong.net/2011/05/powershell-history-persistence.html
http://rkeithhill.wordpress.com/2013/10/18/psreadline-a-better-line-editing-experience-for-the-powershell-console/


Sauron's PowerShell profile in 3 easy steps.


Wouldn't it be nice to share the same PowerShell profile at each of your workstations?  Sharing your influence all throughout Middle-DataCenter...  It's not very tricky, here's how:

1.  Get your cloud syncing app up and running (let Dropbox be the ring-bearer).
2.  Create a location for your one-ring profile, some place like: c:\dropbox\powershell\hobbiton.ps1
3.  Edit your default PowerShell profile to point to the one-ring profile.  So, from the PS command prompt, type:
notepad $profile
   This opens your default profile in notepad... now add this one-liner for the redirection:
. "c:\dropbox\powershell\hobbiton.ps1"
From now on, each workstation can reference the same hobbiton.ps1 profile.  Now your influence can now be felt all across the world.  What sort of influence? say ye fellow traveler...

How about a colored prompt?  BAM:
function Prompt
{
    $promptString = "PS " + $(Get-Location) + ">"
 
    # Custom color for Windows console
    if ( $Host.Name -eq "ConsoleHost" )
    {
        Write-Host $promptString -NoNewline -ForegroundColor Cyan
    }
    # Default color for the rest
    else
    {
        Write-Host $promptString -NoNewline
    }
 
    return " "
}
Sprinkle some of this code magic into your hobbiton.ps1 profile, then set out for an adventure on each of your workstations.



Sources:
http://choorucode.com/2011/09/03/powershell-change-the-color-of-the-prompt/
http://www.asciiworld.com/-Lord-of-the-Rings-.html






Sunday, November 10, 2013

AirPlay to an Arch Linux Raspberry Pi via Shairport

Here's a list of the components:

  • Raspberry Pi - Model B (512 MB / Revision 2)
  • Arch Linux 3.6.11-18-ARCH+
  • some iOS devices (iPhone, iPad, etc)
  • an audio receiver with AUX in


The path of the music:

iOS device -> wifi -> router -> Pi -> 3.5mm output -> receiver input -> speakers -> my living room -> my ears


Here's a few of my notes for getting this up and running... 

Most of this is a modified version of the steps here:
http://engineer.john-whittington.co.uk/2013/05/airpi-diy-airplay-speakers-using-shairport-and-a-raspberry-pi-updated/
I wouldn't say this is an 'updated' version, because I don't know what the hell I'm doing... keep that in mind.

The first few steps are the same:
pacman -Syu
pacman -S kernel26-headers file base-devel abs
pacman -S git
pacman -S avahi libao openssl perl-crypt-openssl-rsa perl-io-socket-inet6 perl-libwww
pacman -S wget
wget https://aur.archlinux.org/packages/pe/perl-net-sdp/perl-net-sdp.tar.gz
tar -zxvf perl-net-sdp.tar.gz

The directory name is different, so...
cd perl-net-sdp
makepkg -s

And the package name is different, so...
pacman -U perl-net-sdp-0.07-1-any.pkg.tar.xz
pacman -S alsa-utils alsa-firmware alsa-lib alsa-plugins
amixer cset numid=3 1
shutdown -r now

After the Pi reboots...
mkdir shairport


The Shairport repo has moved, so use this location:
git clone https://github.com/abrasive/shairport.git shairport
cd shairport
make

Here's where things start to get a little fuzzy.
pacman -S avahi nss-mdns
systemctl restart dbus.service
systemctl |grep avahi-daemon.service

Getting avahi installed and loaded required a little more work.  While trying to start the service it would enter a failed state.  You can check the status with:

systemctl
or more specifically:
systemctl |grep avahi

It wasn't until I found this post:
that said to edit avahi-daemon.conf and change "disallow-other-stacks" from no to yes. 
vim /etc/avahi/avahi-daemon.conf

Find "disallow-other-stacks=no" and change it to yes.  Then try to restart the service:

systemctl restart avahi-daemon
check the status:
systemctl status avahi-daemon

After that, change to the Shairport directory and start it up.  From iOS you should see the new AirPlay device.
./shairport -a AirPi



A little more troubleshooting...

I needed to play around with some of the mixer settings...
pacman -S alsa-utils
alsamixer

Make sure it's unmuted and audio is going out the 3.5mm port:
amixer sset Master unmute
amixer cset numid=3 1


The final step... configure Shairport to run at startup.

following along from the blog post above....

Create the service file for shairport:
vi /etc/systemd/system/shairport.service

Add this text to the file.  If you have shairport in a different location, adjust the ExecStart path accordingly:

[Unit]
Description=Startup ShairPort (Apple AirPlay)
After=network.target
After=avahi-daemon.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/shairport -a AirPi 
ExecStop=/usr/bin/killall shairport
RemainAfterExit=yes

[Install]

WantedBy=multi-user.target

After that, give it a reboot and see if the service starts up ok.  Check the service with:
systemctl