Git and Text Editor Notes for Windows 10

This post is just some notes to remind me how I like to setup a Windows 10 machine for editing scripts.

 

Install and configure Git
First step, install Git. Download the git installer. After downloading, run the installer and accept the default settings.

Then add posh-git for Powershell :
Open a Powershell window “as Administrator” and execute the following :

set-ExecutionPolicy bypass
git clone git://github.com/dahlbyk/posh-git.git
cd posh-git
./install.ps1
. $PROFILE

 

Install and configure Sublime Text
Start by downloading and installing Sublime Text. Accept the default settings during installation.

Next, we want to be able to launch Sublime Text from the command line. To do this we need to make some changes to our environment variables.

First create a new system variable with a name of SUBLIME and a value of C:\Program Files\Sublime Text 3

Add a system variable named SUBLIME and set the value to the path to Sublime Text

Next, Edit the user variable Path and append ;%SUBLIME% to the end.

Now we can simply use subl.exe to launch the editor from a command line.

I like to add some packages to Sublime Text to make it more useful. To do this, first install Package Control. To do this, visit the Package Control site and follow the instructions.

After installing package control, we can install some packages. Open Sublime Text and press Ctrl-Shift-P. Start typing install into the search box and choose Package Control: Install Package You can now search for useful packages. I like to install support for Powershell and VBScript.

 

Reference Links
http://learnaholic.me/2012/10/12/make-powershell-and-git-suck-less-on-windows/
https://scotch.io/tutorials/open-sublime-text-from-the-command-line-using-subl-exe-windows

Powershell Script to Query for Bitlocker Keys in Active Directory

In my organization, we are using Bitlocker to encrypt Windows 7 computers. We are storing the recovery keys in Active Directory, this stores the key as an attribute of the computer object. I recently wanted to generate a report of the bitlocker status of the computer objects in AD. I found out I could do this pretty easily in Powershell, and thought I would document that here.  My inspiration for this script came from this Technet Gallery script

To start, we need the Quest ActiveRoles Management Shell for for Active Directory.   This is available for free from Quest and can be downloaded from here.  This should be downloaded and installed on the workstation that is going to be used to run the script.  With this installed, we are ready to take a look at the script.

# Check to make sure the path has been specified otherwise display a message and exit the script
param([string]$CsvFilePath)
if (!$CsvFilePath) {
Write-Host ""
Write-Host "Path not not specified!"
Write-Host "Please specify the path for the output as a parameter e.g. : "
Write-Host ".\Get-BitlockerComputerReport.ps1 """c:\reports\BitlockerReport.csv""""
Exit
}

Continue reading

Displaying the Bitlocker Wizard Pane with Windows 8 Pro and MDT 2012 Update 1

Using MDT 2012 Update 1 with ADK, I built and captured a Windows 8 Pro image to enable my institution to more easily do some testing with Windows 8. After setting up a task sequence to deploy this reference image I noticed something unexpected. When choosing the Win 8 task sequence, I was not presented with the Bitlocker wizard pane. The wizard pane was showing up fine for my Win 7 task sequences.

I posed the question on the MDT-OSD email list, and Michael Niehaus to the rescue! Turns out there is logic in the MDT scripts to determine if the edition of Windows is a “Premium SKU” to determine what features are available. Since I was using Windows 8 Pro instead of Enterprise it was not getting marked as a premium SKU.

Of course, since Win 8 Pro does support Bitlocker (Win 7 Pro did not), this is a bug. A user posted a bug report to Microsoft along with some work around code. If you have a Connect account, you can see the bug report here.

The work around :

In ZTIUtility.vbs add the following two lines of code after line 3846 :

</p><p></p><p>case "PROFESSIONAL", "PROFESSIONALE", "PROFESSIONALN"</p><p> If Left(oEnvironment.Item("OSCurrentVersion"), 3) &gt;= 6.2 Then IsHighEndSKUEx = True</p><p></p><p>

Update 1-14-2014 :

Hat tip to this Post on MDT2012.com. This bug still exists in MDT 2013 and Windows 8.1 has been released since the writing of this post. The above lines of code have been changed to allow for Windows 8.1 (changed from equal to greater than or equal).

HTA Script for Mapping Network Drives

I had a need for a user friendly Windows script to map network drives using credentials supplied by the user.  The script I endend up with is an HTA script that allows the user to enter their credentials and map a predefined set of network drives.  There is also a button to disconnect the mapped drives.

The script is here : https://github.com/vmiller/ConnectDrives

<!-- HTA script to allow machines that are not joined to a domain to access
     Windows file shares with domain credentials. It will atomatically prepend the
     domain to the username and then map several drives. If a drive is already
     mapped, it is disconnected and then mapped for the current user.
     
     Version 1.0.2
     Written by Vaughn Miller 7/20/2012
     
     Currently setup to map the following drives :
     M: = \\gonzo.ad.messiah.edu\dept
     O: = \\gonzo.ad.messiah.edu\users
     W: = \\mcweb\messiahweb
     ---------------------------------------------------------------------------------->


<HTML>
<HEAD>
<TITLE>Connect Network Drives</title>
<HTA:APPLICATION
ICON="EIPos.ico"
     ApplicationName="MapDrives.HTA"
     SingleInstance="Yes"
     WindowsState="Normal"
     Scroll="No"
     Navigable="Yes"
     MaximizeButton="No"
     SysMenu="Yes"
     Caption="Yes"
></HEAD>

<SCRIPT LANGUAGE="VBScript">

' *** Define Drive Mappings ***
dim arrDrives(2,2)
intMaxdrives = 2

arrDrives(0,0) = "M:"
arrDrives(0,1) = "\\gonzo.ad.messiah.edu\dept"
arrDrives(0,2) = "Dept"

arrDrives(1,0) = "O:"
arrDrives(1,1) = "\\gonzo.ad.messiah.edu\users"
arrDrives(1,2) = "Users"

arrDrives(2,0) = "W:"
arrDrives(2,1) = "\\mcweb\messiahweb"
arrDrives(2,2) = "messiahweb"
' *** End Drive Map Definitions ***

strDOMAIN = "messiah\" 'Domain to prepend to the username


Sub Window_Onload
  '# Size Window
  sHorizontal = 440
  sVertical = 175
  Window.resizeTo sHorizontal, sVertical
  '# Get Monitor Details
  Set objWMIService = GetObject _
    ("winmgmts:root\cimv2")
  intHorizontal = sHorizontal *2
  intVertical = sVertical *2
  Set colItems = objWMIService.ExecQuery( _
    "Select ScreenWidth, ScreenHeight from" _
    & " Win32_DesktopMonitor", , 48)
  For Each objItem In colItems
    sWidth= objItem.ScreenWidth
    sHeight = objItem.ScreenHeight
    If sWidth > sHorizontal _
      then intHorizontal = sWidth
    If sHeight > sVertical _
      then intVertical = sHeight
  Next
  Set objWMIService = Nothing
  '# Center window on the screen
  intLeft = (intHorizontal - sHorizontal) /2
  intTop = (intVertical - sVertical) /2
  Window.moveTo intLeft, intTop
  '# default window content
  window.location.href="#Top"
End Sub


Sub RunScript
   on Error Resume Next

   minUSRnamelength = 2
   minPASSwrdlength = 3

   strUsr = UsrnameArea.Value
   strPas = PasswordArea.Value

   Set objNetwork = CreateObject("WScript.Network")
   Set oShell = CreateObject("Shell.Application")

   If Len(strUsr) >= minUSRnamelength then
      strUsr = strDOMAIN & UCase(strUsr) '<--- adds the domain before the username

      if Len(strPas) >= minPASSwrdlength Then
         Call ClearDrives ' Delete existing mappings if they exist
         
         '***** Begin Drive mapping *****
         For n = 0 To intMaxDrives 'Loop through our array of drives
            Err.Clear
            objNetwork.MapNetworkDrive arrDrives(n,0), arrDrives(n,1), False, strUsr, strPas
            If Err.Number = 0 Then
               oShell.NameSpace(arrDrives(n,0)).Self.Name = arrDrives(n,2)
            End If
         Next
         '***** End Drive Mapping *****
          
         ELSE
            Msgbox chr(34) & strPas & """ is an incorrect password !"
            Exit Sub
         End If
   ELSE
      Msgbox chr(34) & strUsr & """ is an incorrect Username !"
      Exit Sub
   End If
    ' Clean up the objects before exiting
   Set oShell = Nothing
   Set objNetwork = Nothing
   Self.Close()
End Sub


Sub ClearDrives ' Sub Routine to remove the drives if they are already mapped
  On Error Resume Next
  Set objNetwork = CreateObject("WScript.Network")

  '***** Begin section to delete drive mappings ***
  Set AllDrives = objNetwork.EnumNetworkDrives
  For n = 0 To intMaxDrives 'Loop through our array of drives
     For i = 0 To AllDrives.Count - 1 Step 2
        If AllDrives.Item(i) = arrDrives(n,0) Then AlreadyConnected = True
     Next
     If AlreadyConnected = True then
        objNetwork.RemoveNetworkDrive arrDrives(n,0), True, True
     End If
  Next
  '***** End section to delete drive mappings
End Sub


Sub DisconnectDrives ' Calls ClearDrives subroutine and then closes the window
Call ClearDrives
    Set oShell = Nothing
    Set objNetwork = Nothing
Self.close()
End Sub


Sub CancelScript
   Set oShell = Nothing
   Set objNetwork = Nothing
   Self.Close()
End Sub

</SCRIPT>


<BODY STYLE="font:14 pt arial; color:white; filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=1, StartColorStr='#000000', EndColorStr='#0000FF')">
<a name="Top"></a><CENTER>
  <table border="0" cellpadding="0" cellspacing="0"><font size="2" color="black" face="Arial">
    <tr>
      <td height="30">
        <p align="right">Your Username</p>
      </td>
      <td height="30">&nbsp;&nbsp; <input type="text" name="UsrnameArea" size="30"></td></tr>
    <tr>
      <td height="30">
        <p align="right">Password</p>
      </td>
      <td height="30">&nbsp;&nbsp; <input type="password" name="PasswordArea" size="30"></td></tr>
  </table><BR>
<HR color="#0000FF">
 <Input id=runbutton class="button" type="button" value=" Map Drives " name="run_button" onClick="RunScript">
    &nbsp;
 <Input id=runbutton class="button" type="button" value=" Disconnect Drives " name="dis_button" onClick="DisconnectDrives">
    &nbsp;
 <Input id=runbutton class="button" type="button" value="Cancel" name="cancel_button" onClick="CancelScript">
</CENTER>
</BODY>

</HTML>

The drive definitions are coded in an array so that the mapping and disconnecting subroutines can use a loop. To modify this for your own use, you need to modify strDomain (line 50) and the drive definitions (lines 33-48).

I think a nice revision of this script would be to design it to read a configuration file for the domain info and drive definitions. This was one motivation for implementing the array/loop structure.