Saturday, June 21, 2008

Using PowerShell to Retrieve PSTs

Practically every company is going to be involved in a law suit at some point or another. As an IT professional, it's usually our job to help comply with an order to produce copies of email when our company gets sued. In a perfect world, all your employee's email resides in one place and can easily be exported and produced. Back on Earth, employees store their email in a multitude of locations (Exchange servers, local PST files, network PST files, blackberries, etc.) forcing you to exhaustively search all of them for email. Such was the case with my company last month when we received a list of forty or so employees who's email had to be produced. Archiving email from an exchange mailbox is a pretty easy task and doesn't require the employee's cooperation. Archiving PSTs stored on laptops, desktops, and network storage locations is another matter all together. To make the process easier, I decided to write a PowerShell script to automate as much of the process as possible.

Since all I had to start with was a list of employee names, I decided to store all my employee names and search locations in a CSV file. Each line in the CSV file would have the employee's name, their user name, their computer's admin share path, their home folder path, and finally their profile path. A sample CSV might look like this:

"Name", "UserName", "Computer", "Home", "Profile"
"John Doe", "JDoe", "\\Desktop-JDoe\c$", "\\FileServer\Home\JDoe", "FileServer\Profile\JDoe"

Once we create our CSV, we can import it into a PowerShell CSV object. The import looks like this:


Now that we have all of our users and all the network locations we need to search saved into a usable format, we can start writing our PowerShell script. The script itself simply takes in a network location, recursively scans that location for any PST files, adds them to a list, and then attempts to copy those files to a local directory named for the user. If the copy fails, if the PST is locked because that user has Outlook open, or if a search path is unavailable because a user has turned their computer off, then we want to write the skipped PSTs and unavailable search paths to a text file so we can manually track them down later. The quick and dirty version of my script looked like this:
#movePST.ps1
param( $userName, $searchPath, $errorLog )

function copyPST ( $sourcePST ) {
if(!$sourcePST.exists){ $sourcePST.fullname | Out-File $errorLog -Append; return $null }
$error.clear()
Write-Host "Copying " $sourcePST.fullname
Copy-Item -Path $sourcePST.fullname -Destination ($objDestination.fullname + "\" + $counter + $sourcePST.name) -Force
if($error -ne $null){ $sourcePST.fullname | Out-File $errorLog -Append; $error.clear(); return $null }
}

#Check inputs and look for errors
if(!$userName -or !$searchPath -or !$errorLog) {Write-Host "Missing input"; return $null}
$objDestination = get-item ("C:\PSTs\" + $userName)
if(!$objDestination.exists) {Write-Host "Destination folder has not been created: " $objDestination; return $null}
$counter = 1

#record invalid / unreachable search paths
$objSearchPath = Get-Item $searchPath -ErrorAction SilentlyContinue
if($objSearchPath -eq $null){ $SearchPath.toString() | Out-File $errorLog -Append; return $null }

#Look for PSTs and store them in an array
Write-Host "Searching" $userName
$arrayPSTs = Get-ChildItem $objSearchPath -Recurse -Force -Include *.pst -ErrorAction SilentlyContinue
foreach($objPST in $arrayPSTs) {
copyPST($objPST)
$counter += 1
}

The first function actually copies the PST once it's identified. In some situations, the user might have multiple PSTs on their computer with the same name. To solve this, we create a counter, add that number to the beginning of each PST's file name, and increment the counter with each PST we found. If the PST copy fails, the name of the PST is appended to our error log.

The main block of code first does some basic testing of inputs to make sure everything is correctly specified. Once that's taken care of, the script checks the search path. If the path is unavailable (maybe because the user turned off their computer when they weren't supposed t0), then we append that search path to our error log and move on. The last little block of code recursively searches through the search path and sends every PST file to the copyPST funtion to be archived.

Now that we have our script and our CSV containing all our locations, it's time to actually perform the search. Since the script cannot copy PST files that are open inside Outlook, we had to make sure that everyone went home with their computers turned on and Outlook closed. Then we're all ready to start the scan. This example code would search through every entry in our CSV and search each person's computer for PSTs:

foreach ($user in $csv) {./movePSTs.ps1 -userName $user.Name -searchPath $user.Computer -errorLog ./error.txt}

To search the profile and home paths, you would run the same code but substitute $user.Home and $user.Profile for the $user.Computer parameter. If all goes well, you wind up with a folder containing all the CSVs organized by name. Any errors show up in the error.txt file and can be archived later.

One final note: Depending on the industry you're in, your company may have to frequently produce emails. If this might be a possibility, make sure you take that into account when you come up with IT policies regarding email and PSTs. You should also spend some more time figuring out the best ways to archive email and which of those steps you can automate with PowerShell. The last piece of the puzzle is training your users on what to expect when you perform an email archive. Their cooperation makes the process much easier. Happy litigating!

Saturday, June 14, 2008

Setting up a DMZ in ESX 3.5

One of the strongest selling points for using ESX as a lab environment is the ability to quickly create and modify network configurations to replicate practically any network layout you wish. What would take a few hours in a lab running network cable and configuring switches and routers can be done inside ESX with a few clicks of the mouse. For today's post, I will walk you through the basic steps of creating a DMZ inside your ESX server. Since this is a lab environment only, our focus will be on creating a functioning DMZ rather than worrying about security.

The first step, as in any network setup, is planning. I know I generally like to dive right into any new project and start creating, but this is one instance where a few minutes of planning will save you hours of headaches later down the line. I use the same spreadsheet to track IP address assignments in my lab environment that I use in my production environment. Write down each IP address range you plan on using and it's specific use and method of assignment (static or DHCP). I generally allocate the first 10 IP addresses to routers, switches, and other networking devices. I reserve addresses 10-30 for statically assigned servers. I usually create a DHCP zone that assigns the 100-200 address range. Lastly, I reserve 90-99 for any special devices that I have statically assigned via DHCP lease reservations. The result should look something like this:


On a separate sheet, record any statically assigned IP addresses, the host they belong to, and any notes that might be helpful. This makes it easy to tell at a glance which static IP addresses are free when you start adding servers. Make sure you and anyone else making changes to your lab environment keep the worksheet updated. All this planning may seem like overkill at first, but your test lab can quickly become too complicated to keep everything in your head.



Now that we have a blueprint for our DMZ, we're ready to decide what devices we need. A physical DMZ requires at least some network cables, a router, a switch, and a server to access. Our virtual DMZ will have the same components. ESX will provide our virtual switch as well as handling any cabling that needs to be done. You have a couple of choices when it comes to the router you wish to use. A Windows Server 2003 virtual machine set up with the routing and remote access service will suffice for the most basic routing needs. My personal preference is the Astaro Security Gateway appliance available from Astaro. They offer a free personal use license that supports up to ten clients. The ease of use and the list of features is pretty astounding for a free product. The specifics of installing the Astaro virtual appliance are beyond the scope of this article, but the download includes detailed instructions for installing the virtual appliance on ESX.

Now that we have a plan laid out for our virtual network and we have the router selected, it's time to start creating the switches and network connections inside ESX that will form our DMZ. Start up the VMware Infrastructure Client and log into your ESX machine. Highlight your ESX server on the left side of the screen and select the "Configuration" tab. You should be presented with your current ESX network layout that looks roughly like this:

If you're new to using virtualization, the network configuration can be a little confusing at first. ESX displays your virtual network setup so you can think of it just like a physical network. The left hand side shows all the virtual machines connected to your virtual network. The vertical grey bar represents the virtual network switch connecting all those virtual machines together. The right hand side shows any physical adapters that allow your virtual network to connect to outside networks. As you can see in our current configuration, I have virtual network called LAN with a half dozen virtual machines connected. The LAN network has a single physical network card attached to allow those virtual machines access to the outside world. For our purposes, we will assume that your initial network looks similar to mine and that the virtual machines in your existing virtual network can access the internet.

Now we're going to create the virtual network for our DMZ. Click on the "Add Networking" link. The next dialogue box asks you what type of network connection you wish to add. We want a new virtual switch to attach our virtual machines so we're going to select "Virtual Machine" and click "Next". The next dialogue box asks you whether you want to create a new virtual switch or connect to one of your current virtual switches. We'll leave the default "Create a virtual switch" option selected. ESX automatically adds any unassigned physical network adapters to your new switch. Make sure you clear any of the check boxes since our DMZ will only be connected to the outside network via our router. Take a look at the preview to be sure your new virtual network is set up the way you wish.


In the next dialogue box, give your new virtual network a name. We'll call ours DMZ. Leave the VLAN option blank and click "Next". We're now back at the configuration tab. Once ESX finishes creating our new virtual network, we should have something like this:

Our old LAN network is displayed on top with the newly created DMZ network just below it. We're almost finished. We've created the DMZ virtual network, but we still have to add our router and some virtual machines. The specific steps for installing your router depend on which type you selected. Regardless of what you decided to use as your router, you will need to make sure your router virtual machine has at least two virtual network cards. Your router will need at least one network adapter in the DMZ network and one network adapter that has access to the internet to function propertly. Once you finish installing your router, you can start adding virtual machines to your DMZ network. Once you add a virtual machine or two, go back to the configuration tab for your ESX server. If everything went to plan, you should see your router and the virtual machines you added under the DMZ virtual network.

One final note. We created this virtual DMZ with functionality instead of security in mind. The purpose of a true DMZ is to allow some of your servers greater access to the internet while keeping the rest of the network secure. This separation limits the damage in the event someone is able to breach one of the servers in your DMZ. In our virtual environment, our DMZ servers run on the same ESX hardware as the rest of our virtual servers so the same level of isolation is not created. This virtual DMZ is perfect for a lab environment, but further attention to security should be paid before using your virtual DMZ in any kind of production environment.

Wednesday, June 11, 2008

Remotely Launching Goto Assist with PsTools

Like many IT departments, remote assistance using Goto Assist or another similar product is a cornerstone of our support infrastructure. Goto Assist in particular is extremely versatile as it works through most firewalls and can be launched by sending the client an email containing a link or by having them go to a customized web page and typing in a code. Even with the various built-in options for initiating a remote assistance session with Goto Assist, I still find situations where it's more desirable to remotely launch a session without any user intervention at all. Assuming the client computer is a member of our domain and we can actively contact that computer over the network, you can accomplish this task using the PsExec command included with PsTools. If you haven't gotten familiar with the PsTools suite, I highly recommend you check them out. They are invaluable for managing remote workstations in a windows domain.

PsExec allows you to remotely execute a command on a domain member workstation. To launch the Goto Assist session, we're going to remotely launch internet explorer and tell it to open the URL associated with our Goto Assist session. Here's an example:

psexec \\ClientComputerName -u DOMAIN\User -i "C:\Program Files\Internet Explorer\iexplore.exe" http://www.google.com

Replace ClientComputerName with the name of the workstation you wish to connect to. If you're authenticating with a domain account, use the DOMAIN\User format for the -u switch. You can use a local account that exists on the client computer simply by using that name with the -u switch. This example launches Google's web site, but you can replace that URL with the link to your Goto Assist session. The -i switch forces the application to launch in interactive mode so the user can see the window.

There are a few security issues to keep in mind. You will want to ensure the user account you use to launch Internet Explorer has only the minimum permissions required since the IE process will run with all the permissions that user possesses. If, for example, we ran this command and input an account that had local administrative rights on the client computer, anything the client did with that IE window after we launched it would also have full administrative rights. We have a local user account on all our workstations I use to launch Goto Assist since it needs no special administrative permissions. We could also purposely launch IE using a local administrative account for the purposes of allowing the user to install a new ActiveX control. Just be sure to define your security policies for this procedure ahead of time and stick to them.

Monday, June 9, 2008

PowerShell Script to Compute Folder Sizes

I would like to preface this post with a disclaimer. While I have a few languages under my belt, I'm fairly new to PowerShell. Most of my posts on this topic will simply be scripts that I've created or modified for my own purposes. Feel free to use any of them for whatever purpose you choose.

I created this function as part of a larger script I'm writing that archives old users in Active Directory. I needed a way to report the profile size of the archived user and flag large profiles for closer inspection to save on disk space. This code is a modified version of a script I found on Z@RAYS. I'll talk more about the specific changes I made a bit later.

function folderSize ( [string] $folderPath )
{
if($folderPath)
{
#Initialize everything
$totalSize = 0
$folderRoot = Get-ChildItem $folderPath

#Total the subfolder sizes
foreach($folder in $folderRoot)
{
if($folder.mode -match "d")
{
#Retrieve the folder size and add it to the running total
$fsz=((Get-ChildItem $folder.fullname -Recurse -Force | Measure-Object length -sum).sum)
$totalSize = $totalSize + $fsz
}
}

#Add the size of items in the folder root
$filesize=(($folderRoot.fullname | Measure-Object length -Sum).sum)

#Convert to GB and format to 2 decimal places
$totalSize = ($totalSize + $filesize)/1GB
$totalSize = "{0:N2}" -f $totalSize
return $totalSize
}
}
The first section of code initializes our running total to zero and creates an object representing the root folder who's size we want. The second section recurses through each sub folder and adds the size of that sub folder to our running total. Now that we've got the sub folder size, the next section adds the size of any files that happen to be stored in our folder's root. The last section converts the total size to GB and truncates the result to two decimal places before returning the total size.

The primary change I made from the code found on Z@RAYS is in the rounding of our folder size. The original code formatted each sub folder's size into GB with two decimal places before adding it to the total. I found that in situations with large numbers of sub folders, this could introduce a significant rounding error. Saving the formatting for last eliminated that problem. I also wanted my result in GB instead of MB, but this code can easily be modified to return the result in any unit you choose.

Friday, June 6, 2008

Cheap VMware ESX Server - Part 2

The parts arrived from newegg this week. As with any computer assembly, the first step is to lay everything out and take an inventory to see if anything is missing. Here's the stack of parts laid out on the kitchen table.


The next step was to prepare the drawer with some ventilation. I decided to try a single 80mm intake fan mounted onto the back of the drawer with an intake hole cut through the thin cardboard on the back of the ikea cabinet. The fan is mounted on the back of the drawer so it sticks out through the back of the cabinet when the drawer is closed. This ensures you are drawing in cold outside air. I held the fan to the back of the drawer and used a pencil to mark the screw locations and the air hole. A dremel with the drill and routing tools worked fairly well to finish the wood working. Here's a few pictures of the finished drawer with the 80mm fan mounted in back.


Now comes the fun part; putting everything together. I tried to keep the heat-producing components along a straight line between the front of the drawer, which I plan to leave cracked for heat exhaust, and the intake fan at the rear of the cabinet to provide optimum air flow. I added a temporary CD-ROM for the OS installation. While the motherboard has onboard SATA ports, you will need to be sure to connect your hard drives to the SAS ports or the ESX installer won't be able to locate the disks.


Once everything is in place, temporarily connect a VGA cable and a keyboard for the initial setup. Unless you have a power button to use, carefully use a screwdriver to short the two power pins on the front panel to power on the server. I like to boot into BIOS first to give everything a quick look over and change any settings. At a minimum, ensure the motherboard correctly identifies your processor type and memory quantity. If not, you may need to flash the BIOS. I also set the BIOS to default to power on after a power loss. This means if the power goes out for some reason, the system will start right back up. Now is also a good time to set the temp and fan speed warnings so your server won't overheat and damage itself inside the drawer. Once everything in BIOS checks out, boot to the SAS RAID manager and create your array. Be sure to make it bootable. Boot to the ESX installation CD and verify the installer can see the local drive.

Now that ESX is installed, your lab server is ready to go!

On a final note, the single intake fan wasn't enough to keep the drawer cool. I noticed that the intake fan wasn't running at full speed while connected to the motherboard, so I attached it directly to the power supply using an adapter. This helped a little, but still not enough as the ambient temp inside the drawer was peaking at 110 F under idle conditions. In the mean time, I'm going to run the server with the drawer cracked a few inches. I'm hoping to add another fan this weekend to solve the problem.

Cheap VMware ESX Server - Part 1

Sunday, June 1, 2008

Cheap VMware ESX Server

With the release of VMware's ESX 3.5, a very cheap but extremely powerful test server can be had for around a thousand dollars. I was in need of an ESX server to host at least 8-10 virtual servers as a training tool for my MCSE exams. Having been inspired by an article on building a linux cluster in an Ikea Helmer cabinet, I decided to build my server into an Ikea Malm cabinet.

The most difficult item to find is going to be the motherboard. ESX 3.5 only supports SATA hard disks on controllers that also support SAS drives. Newegg only had a few boards to choose from and they're all in the $300 - $400 range. I went with the quad core instead of a dual core because the price difference was fairly insignificant. As with most virtual hosts, the physical memory decides how many virtual machines you can host. I needed at least 8-10 VMs, so I maxed out the motherboard with 8GB of RAM. The pair of SATA disks allows for a RAID 1 configuration. This isn't strictly necessary for a lab environment, but it doesn't hurt. If you wanted to cut some costs on the hardware, select a dual core processor, only buy 4GB of RAM, and ditch one of the hard disks. Here's the shopping list from Newegg:

Asus P5BV-E/SAS Motherboard $310
G.Skill 4GB (2x2GB) DDR2 Memory (x2) $170
Apevia 500W Power Supply $40
Western Digital 500GB SATA2 Hard Disk (x2) $110
Intel Xeon X3220 Quad Core 2.4GHz $235

That brings the hardware total to $1145 excluding shipping. The Malm cabinet ran me another $80. Ikea had plenty of other cheaper cabinets that would fit the bill, but this one better matched my room's decor. Either way, it's a lot cheaper than a server case and it has room for my socks. I will post more details and some pics once I get the server up and running.

Cheap VMware ESX Server - Part 2