Configuring the PowerShell ISE for use with Git and GitHub

The goal of this blog article is to configure the PowerShell ISE (Integrated Scripting Environment) so the management of Git version control can be performed from it. Most tutorials you'll find will attempt to lead you down the path of using SSH instead of HTTPS to synchronize your repositories to GitHub from the command-line but that's really over-complicated and unnecessary if you're using a Windows based machine.

The client machine used in this blog article runs the 64 bit version of Windows 10 Enterprise Edition. Windows 10 has PowerShell version 5 installed by default. Git for Windows version 2.7.0 and Posh-Git version 0.5.0.2015 are the third party software versions used in this blog article.

The first question you may ask is why not just use the Git Shell that's installed as part of GitHub Desktop? While it's true that you can launch Git Shell and then the ISE from it, the problem is that Git Shell uses the x86 (32 bit) version of PowerShell on a machine with a 64 bit operating system which means you won't have all of your PowerShell modules available and that's a solution that ends up being a sub-par experience. What I want to accomplish is simple, to launch a PowerShell ISE session as I always do and then to be able to manage both local Git repositories as well as remote ones on GitHub.

If you've installed GitHub Desktop, then you already have a copy of the Posh-Git PowerShell module and a portable version of Git installed which are located in subfolders of $env:LOCALAPPDATA\GitHub in your user's profile. I chose not to use those versions and to go ahead and install them for all users in the program files folder since I'm running PowerShell elevated as an alternate user (I login to Windows as a standard user and run PowerShell elevated as a local admin). You could also manage your GitHub repositories using this process without ever having to install GitHub Desktop.

First, install and configure Git for Windows. I previously covered this topic in another blog article. In this scenario, I ran the Git installer elevated so I could install it in the program files folder and I took the option to add the path for Git to the system environment variable path:

posh-git0a.png

Make sure that you've configured Git as the user who is running PowerShell (I ran these commands from within my elevated PowerShell session):

1git config --global user.name 'your name'
2git config --global user.email 'your email address'
3git config --global push.default simple

I used my private GitHub email address instead of my personal public email address to eliminate the possibility of spam. For more information on this topic, see the GitHub help article on Keeping your email address private.

Install the Posh-Git PowerShell module from the PowerShell Gallery:

1Install-Module -Name posh-git -Force
2Get-Module -Name posh-git -ListAvailable

posh-git1a.png

I created a custom profile script that changes my PowerShell prompt depending on whether or not I'm in a directory that's part of a Git repository. There is a default profile located in the Posh-Git module folder, but I chose not to use it for a number of reasons, one of which is that I wanted to retain the ability to show a nested prompt and I also wanted the prompt to look similar to Git Bash when working with a Git repository. The one in the Posh-Git folder also generates an error because it attempts to setup an SSH agent which is not available in the version of Posh-Git that's installed from the PowerShell Gallery. See the version on GitHub if that's something you're interested in, but as you'll learn in this blog article, the SSH agent is unnecessary.

I setup this profile to run for all users and all hosts on my machine since I often run PowerShell as an alternate user and I want it to be available from the PowerShell console and ISE:

 1Set-Location -Path $env:SystemDrive\
 2Clear-Host
 3
 4$Error.Clear()
 5Import-Module -Name posh-git -ErrorAction SilentlyContinue
 6
 7if (-not($Error[0])) {
 8    $DefaultTitle = $Host.UI.RawUI.WindowTitle
 9    $GitPromptSettings.BeforeText = '('
10    $GitPromptSettings.BeforeForegroundColor = [ConsoleColor]::Cyan
11    $GitPromptSettings.AfterText = ')'
12    $GitPromptSettings.AfterForegroundColor = [ConsoleColor]::Cyan
13
14    function prompt {
15
16        if (-not(Get-GitDirectory)) {
17            $Host.UI.RawUI.WindowTitle = $DefaultTitle
18            "PS $($executionContext.SessionState.Path.CurrentLocation)$('>' * ($nestedPromptLevel + 1)) "
19        }
20        else {
21            $realLASTEXITCODE = $LASTEXITCODE
22
23            Write-Host 'PS ' -ForegroundColor Green -NoNewline
24            Write-Host "$($executionContext.SessionState.Path.CurrentLocation) " -ForegroundColor Yellow -NoNewline
25
26            Write-VcsStatus
27
28            $LASTEXITCODE = $realLASTEXITCODE
29            return "`n$('$' * ($nestedPromptLevel + 1)) "
30        }
31
32    }
33
34}
35else {
36    Write-Warning -Message 'Unable to load the Posh-Git PowerShell Module'
37}

The latest version of my profile script can be found in my PowerShell repository on GitHub. That repository is where I keep my PowerShell code I want to share publicly that doesn't fit into more specific categories. I have dedicated repositories for Active Directory, SQL, etc. If you're not placing your profile script in source control, why not?

I'll clone my PowerShell repository from GitHub to my local computer:

1git clone https://github.com/mikefrobbins/PowerShell.git PowerShell -q
2Set-Location -Path .\PowerShell

posh-git2a.png

Notice in the previous example that the prompt changed once I entered the PowerShell folder. That's because of the custom profile script and this folder being part of a Git repository. If I were to change to another folder that's not part of a Git repository, my prompt would change back to the default PowerShell one.

Getting the status of this repository shows that it's up to date with the remote and you can also see the details of where the remote is located on Github:

1git status
2git remote -v

posh-git3a.png

The problem at this point is the ISE generates some weird error message that you'll find all sorts of suggestions when searching on the Internet for solutions, but unfortunately all of the recommended fixes are a dead-end.

1git push

posh-git4a.png

1git : bash: /dev/tty: No such device or address
2At line:1 char:1
3+ git push
4+ ~~~~~~~~
5+ CategoryInfo : NotSpecified: (bash: /dev/tty:…vice or address:String) [], RemoteException
6+ FullyQualifiedErrorId : NativeCommandError
7error: failed to execute prompt script (exit code 1)
8fatal: could not read Username for ‘https://github.com’: Invalid argument

At this point, you need to punt and go back to the PowerShell console to perform a few tasks that will end up resolving the problem that you're experiencing in the ISE.

Running the same command from the console appears to work, but due to having two-factor authentication enabled on your account, the authentication will fail. Notice that I didn't say if you have two-factor authentication enabled on your account because in this day and age you better have two-factor authentication enabled or you're asking to have your account hacked.

1git push

posh-git5a.png

See this blog article on GitHub to learn more about setting up two-factor authentication on your GitHub account.

Create a "Personal access token" in your GitHub account that will be used for authentication at the command-line:

posh-git6a.png

See this GitHub help topic to learn more about setting up a Personal access token for command-line use. Make sure you read about limiting the scope of this token before continuing. See the GitHub Developer OAuth API documentation to learn more about what each scope option authorizes.

Using the token as the password works without issue except it has to be entered each time a command is run that requires authentication to GitHub:

1git push

posh-git7a.png

To prevent having to enter the token each time, enable the credentials to be saved to Windows credential manager:

1git config --global credential.helper wincred

posh-git8a.png

For more information about the command used in the previous example, see the Caching your GitHub password in Git help topic on GitHub.

The next time the token is entered as the password, it will be saved to Windows credential manager and you'll no longer be asked for a userid / password combination when running a command that requires authentication to GitHub.

1git push
2git push

posh-git9a.png

Switch back to the ISE. Running the same commands that previously generated the cryptic error message now run without issue. It appears that they generate errors but these are due to Git sending much of its output to StdErr instead of StdOut so they can safely be ignored:

1git status
2git push
3Set-Location -Path ..\AWS
4git status
5git push

posh-git10a.png

1git : Everything up-to-date
2At line:1 char:1
3+ git push
4+ ~~~~~~~~
5+ CategoryInfo : NotSpecified: (Everything up-to-date:String) [], RemoteException
6+ FullyQualifiedErrorId : NativeCommandError

Notice that in the previous example, you can now push to any of your GitHub repositories without being prompted for authentication. You might be wondering where the saved credentials are stored at? They're stored securely in Windows credential manager:

1cmdkey /list

posh-git11a.png

Use caution when changing branches and having files from a Git repository working folder open in the ISE. You could unknowingly overwrite files in one branch with files from a different branch. My recommendation is to close any open ISE tabs containing files from a Git repository working folder before switching branches.

You'll find that you'll be much more likely to place your PowerShell scripts, functions, and modules in source control now that you can manage the version control system right from the same interface that you're writing your code in.

Additional GitHub help topics worth mentioning: Git automation with OAuth tokens and Personal API tokens.

Update 2/20/16:

Based on a number of responses I received on Twitter, there are several reasons you might want to use SSH instead of HTTPS. Most of these use cases fall outside of the scope that my blog article was originally intended for, but I still wanted to make you aware of them: (1) You hop between different operating systems, (2) you shuffle between different services such as GitHub, GitLab, and Gogs, (3) you're using on-premises SSL: Adding a corporate (or self-signed) certificate authority to git.exe’s store.

Update 2/21/16:

I decided to do a little more research on the subject of which protocol to use for accessing GitHub from Git based on my previous update since those tips came from people in the industry that I have a great deal of respect for. My research lead me to a help page on GitHub on how to Set Up Git which is self explanatory:

posh-git13a.png

There are definitely some considerations to keep in mind and reasons you would want to use SSH over HTTPS which is probably why they make it available, but I have a difficult time going against the recommendation to use HTTPS from the software manufacturer considering this blog article focuses specifically on accessing GitHub from Git.

µ