Using Find-String to grep in Powershell

For the longest time I have not been a fan of embracing the shell in the Windows world, but more and more I find that Powershell is able to do the things that I need.  I suppose my seething hatred was in part due to my negative bias towards Windows and the lack of useful tools from the command line in Windows.  Increasingly lately, I have been changing the way I think about and utilize the command line in Windows with Powershell.  And to be honest, I’m really beginning to fall in love with Powershell the more I get work with it and the more I get to see how to apply it in Windows based environments.  The good news is that Microsoft has put a lot of effort into this and are adding improvements and features all the time.  It still has a long way to go, but I can already see this as an alternative to GUI based administration in the Windows world and finally begin to feel like I can see the promise land on the horizon.  Using Powershell has been somewhat of a paradigm shift (in my opinion anyways) to how to do Windows administration recently and I feel like it will only get stronger and more common in the years to come.  So in this post I will try to show you some of the flexibility as well as some of the power that Powershell has to offer with some great tools from the community.

To highlight what I am talking about, let’s talk about grep, a well known and loved tool in the *nix universe.  I love grep.  For the longest time, I hadn’t known of a way to grep in the Windows world until just recently with a wonderful third party Powershell module called Find-String.  There are a few commands that you need to get this working.  To start, we need to get a module installed that is basically used for package management.  This tool is called PsGet. Installation is super simple, just run the following from a Powershell prompt, and ensure that your execution policy is set at least at remotesigned (Set-ExecutionPolicy RemoteSigned if you don’t have this turned on).

(new-object Net.WebClient).DownloadString(“http://psget.net/GetPsGet.ps1“) | iex

This should go out, download and install PsGet for you.  Once all that has completed you should be able to install Powershell modules that are contained in the PsGet repository.  With this installed we can just reach out to the PsGet repo and install our module.

Install-Module Find-String

Easy, simple, and clean.  That is the best part, there isn’t a ton of leg work to get this stuff working correctly and is why I’m enjoying Powershell so much these days.  Now we have a very functional grep clone!  Usage is quite a bit similar to grep, fore help you can do a Get-Help Find-String or look at the link I posted earlier to the author’s github page.  If you want to look for a word or substring in a file just use something like this:

Find-String word example.txt

This will output all occurrences of the word you are looking for in the file example.txt.  Here is a screen shot to show you.

Find-String in action

What other cool Powershell stuff are you doing?  I would love to hear about other cool uses that can be beneficial in every day use.

Read More

Protip December: Customize your Powershell profile

Powershell is great but is a little boring if anything, out of the box, with its drab white foreground and all.  It isn’t exactly informative either, so I wanted to show everybody a quick trick to customize this look and feel to make things look a little bit cleaner.  Hopefully this introduction will demonstrate one of the many features that makes Powershell a great tool for Windows admins, which is its flexibility.

This customization file, called profile.ps1 can be located in one of two places.

  • The first location is the global location and would be useful when you want all users to have a customized Powershell profile.  This profile should be placed in C:\WINDOWS\system32\WindowsPowerShell\v1.0\Profile.ps1.
  • The second location is for the local profile and would be specific to each user account.  This file overrides the global configuration file and should be placed in C:\Username\My Documents\WindowsPowerShell\Profile.ps1.

By default these files don’t exist so you will have to navigate to the respective directory and create the initial, empty profile.ps1 file.

Once you have the file created just pop this chunk of code into your profile.ps1 file.

function prompt {
	$path = ""
	$pathbits = ([string]$pwd).split("\", [System.StringSplitOptions]::RemoveEmptyEntries)
	if($pathbits.length -eq 1) {
		$path = $pathbits[0] + "\"
	} else {
		$path = $pathbits[$pathbits.length - 1]
	}
	$userLocation = $env:username + '@' + [System.Environment]::MachineName + ' ' + $path
	$host.UI.RawUi.WindowTitle = $userLocation
    Write-Host($userLocation) -nonewline -foregroundcolor Green 

	Write-Host('>') -nonewline -foregroundcolor Green    
	return " "
}

Once you have this bit added you will need to reload Powershell and voila,

Customized powershell look
Here’s our customized Powershell look.

Much better.  As you can see we now have some additional, out of the box information including:

  • Our current username – jreichardt
  • Our computer name – JOSH-TEST
  • Our current directory – separated by the | (pipe) symbol
  • As well as a nice green foreground font to help with the readability.

Pretty simple to get set up but definitely adds a lot to the default look and feel.  Let me know if you have any other cool Powershell customization’s or tricks that you think are worth sharing.

Read More

Restore an Exchange Mailbox Database using Data Protector

Forgive the boring title for this post but I do think that this is a really important topic and one that I had to deal with recently at work.  Somehow one of our Exchange mailbox databases became corrupted and one of our users lost a ton of email, which, I’m almost 100% sure was related to the outage catastrophe we experienced 1.5 weeks ago.  This event made me thank the Flying Spaghetti Monster that I was getting good backups from our (sometimes shaky) backup solution, Data Protector.  Anyway, for this topic I will just assume that you are getting backups from whatever backup solution but it isn’t all that important because the majority of this post will cover specific instructions for the procedure within Exchange, so you can take bits and pieces and apply them where you need to.

Before I go any further, it is always worth mentioning;  make sure you are getting good backups! 

Ok, now that we have that out of the way I will show you the basic restore procedure within the Data Protector environment.  Select the Restore option from the drop down list -> MS Exchange 2010 Server.

Then select the source to backup up (Whichever database that needs to be restored).  With in Data Protector specify the restore options that you would like.

These are the options I used most recently.

  • Restore method: Restores files to temporary location
  • Backup version: Whichever data you decide you need to roll back to
  • Restore chain: Restore only this backup
  • Target client: Select the mailbox server that you want to restore to
  • Restore into location: This can be any location, just make sure there is enough disk space.
  • Select Restore databse file only

Once you have chosen your restore options, click the restore button to begin the restore procedure.

Once the database has been restored with Data Protector

Now for the fun stuff.  This is the part that I’m guessing most will probably be concerned with, but I didn’t want to leave out my Data Protector peeps.  Open up an Exchange Management Shell on the mailbox server that you restored your database to.  Technically it can be from any server as long as you connect to the correct mailbox server I guess.  Anyway, rename your restored database to something like “recoverydb.edb”.  Change directories into the restore folder, then check the status of the newly restored database with the following command:

eseutil /mh recoverydb.edb

You should see something similar to the following:

If it shows Clean Shutdown you can skip ahead.  Since we didn’t bring any log files down with us in this restore we will need to run the database hard repair on this database using the following command:

eseutil /p recoverydb.edb

After running the repair you should get a clean shutdown state if you check again (eseutil /mh).

Now we need to create a recovery database for Exchange to use in order to recover this data from.

New-MailboxDatabase -Recovery -Name “recoverydb” -Server Mailbox1 -EdbFilePath “M:\recovery\recoverydb.edb” -LogFolderPath “M:\recovery” -Verbose

It is important that when you create your recovery database it matches the renamed .edb file.  So since I renamed my recovery database to recoverydb.edb, I used recoverydb in the Powershell command.  If you want to check to make sure this step was done properly, use the following command to verify that the database is roughly the size you are expecting it to be:

Get-MailboxDatabase -status | select Servername,Name,DatabaseSize

After everything looks good we mount our database.

Mount-Database recoverydb

Just to verify that the database has stuff in it and we can find the person we’re looking for, we will take a quick look at the database contents, as shown below.

Get-MailboxStatistics -Database recoverydb

It looks like there are users there so all we need to do now is dump their emails into a temporary/recovery account in Exchange with the following command:

Restore-Mailbox -RecoveryMailbox “user_to_recover” -Identity “temporary_account” -RecoveryDatabase recoverydb -TargetFolder “RecoveredItems”

  • -RecoveryMailbox is the user mailbox that we are pulling data from, the source mailbox
  • -Identity is the user mailbox that we are putting data into, the destination mailbox
  • -RecoveryDatabase is our newly created recoverydb
  • -TargetFolder is the a folder that we will create on the target user to house the recovered items
  • -Verbose optional debugging information if there is a problem anywhere in the process

The wording and syntax of this command is a little bit tricky.  Just remember that the -RecoveryMailbox signifies the backup location and the -Identity signifies the restore location.  After this process completes (could take awhile depending on the mailbox size) you should be able to log in to the temporary account and take a look at the newly created “RecoveredItems” folder in which the mailbox contents of the user mailbox we are restoring have been copied in to.

Once this is done, just right click the target mailbox (temporary_account), click Manage Full Access Permission and give the restore mailbox (user_to_recover) full permissions through the Exchange Console so you can copy over messages, etc. in Outlook.

This step can be done any number of different ways but I chose this method because I was more concerned about the safest way to do this.  You could, for example, copy the contents directly into the user mailbox if you wanted.  Another option would be to export the contents of the temporary user out into a .pst file, with something like the following:

New-MailboxExportRequest –Mailbox mailboxserver –FilePath \recovery.pst

That should be it, after you are done and the emails have all been recovered , be sure to dismount the recovery database and delete the files to free space back up on your mailbox server.

Resources:

http://blogs.perficient.com/microsoft/2011/02/working-with-exchange-2010-recovery-databases-2/
http://www.mikepfeiffer.net/2011/07/restoring-mailbox-data-from-a-recovery-database
http://pmirmand.files.wordpress.com/2011/08/restore-database-on-exchange-2010.docx

Read More

Sending Test Emails with Telnet

I’d like to talk quickly about a great and underutilized method for troubleshooting email flow problems.  Today I had to rebuild an Exchange Hub Transport server after a slight catastrophe from last week in which the VM the Hub lived on was completely unrecoverable.  That is another story but it brings up the need for using a great tool that is often skipped over, and that is sending test email via telnet.

The reason I say that this method is underutilized is because, well who uses telnet these days?  What’s great about using this is that you can test different aspects and essentially pinpoint where mail flow issues are occurring.  In my case I was have trouble relaying email from an internal account to outside mail servers.  So let’s jump into how to use this tool, its easy but I feel like not enough people know about it, so here we go.

First, since I was testing from inside, I need to connect to the local server name.

telnet hubserver.psa.local 25

Easy enough, we are using telnet to connect to the hub server, hubserver.psa.local on port 25 (SMTP).  Once we get in we run a simple,

ehlo

That gives us back a little bit of information, basically telling us that this is an email server and some of its capabilities.  Next, we will need to run through the following set of commands to send out the test email.  It is important that these commands are entered in exactly, with no backspaces, otherwise it will break the command and you will get an error message spit back out from your telnet session.

MAIL FROM: [email protected]
RCPT TO: [email protected]
DATA
SUBJECT:

message content.

.
QUIT
  • MAIL FROM: This is telling the mail server who this message is being sent from.
  • [email protected] is the internal mail sender I was using.
  • RCPT TO: Tells the mail server the email address that is being sent to.
  • [email protected] is the address we are sending to. It can be any of your internet based mail addresses (google, yahoo, etc.).
  • DATA signifies the start of the message body.
  • SUBJECT: This line is optional, probably a good idea to include a subject so the message doesn’t get blocked or sent to spam.  Hit enter twice after this to drop into the message content.
  • message content is whatever you want to include in your message.  Follow your message by hitting enter.
  • “.” (read dot) on a line by itself will tell the mail server to end the message and send it.  It is basically the equivalent of an escape character for emails.
  • QUIT leaves the telnet session from the mail server.

It is important that the previous set of commands is run the way that they look.  This whole string of commands should look something similar to the following inside of your shell when things are all said and done, assuming everything is working properly.

In my case, I was unable to enter an address for the RCPT TO: command.  To fix this, among with a few other steps in rebuilding the hub was to grant anonymous send permission on the Exchange side of things, then after that mail began flowing through the newly rebuilt Hub Transport server perfectly.

That should be it, I highly suggest going through the process of sending out a few test emails to get this method stuck in your brain for later on down the road if you ever have to do any mail flow type troubleshooting.  Good luck!

Read More

Quickly Add Users to Lync 2010 Environment

Update (10/11):  new script posted

I had the chance to work on this script a little bit more and was able to add a few of the features and checks that I wanted originally such as the ability to check if a user is a member of Active Directory or not, if the user is already of member of the Lync environment and also a very simple logging mechanism to gather information on names that weren’t in AD, users already in Lync, etc. to make life easier if the script has been run but there were misspellings or whatever other anomalies in the CSV file that is read in.

The format for reading in users is exactly the same, so just look at the example CSV file posted at the bottom of the page to get an idea of how users should be entered and look in the file for getting read in properly.

The updated code is posted below.  I will be adding this onto my github account in the future as well so check out github if you aren’t already a member.

##======================================================================================
##Script:  EnableLyncUsers.ps1
##Name:    Josh Reichardt
##Email:   [email protected]
##Date:    10/9/12
##Purpose: Use this script to add users already in AD domain into Lync 2010 environment.
##Notes:   Reads in a CSV file with pre populated AD Display names.  Can be adjusted to
##	   work with alternate AD names (eg SIP address, UPN or AD log on name).
##======================================================================================

#Variables.
$File = "C:\Lync\test.csv"
$Log = New-Item -ItemType File -Path "C:\Lync\userlog.txt" -Force

#Import CSV File
$UserArray = Import-CSV -Path $File

#Check if user file is empty.
if ($UserArray -eq $null)
{
	 write-host "No Users Found in Input File"
	 exit 0
}

#Get total number of users in CSV file and begin proccessing.
$count = $UserArray | Measure-Object | Select-Object -expand count
Write-Host "Found " $count "Users to import."
Write-Host "Processing Users.....`n"
$index = 1

ForEach ($User in $UserArray) {

	Write-Host "Processing User " $index " of " $count
	$Fullname = $User.DisplayName
	$aduser = get-csaduser -Identity $Fullname

	#Check if user is in AD.  Log if they are NOT.
	if ($aduser -eq $null) {
		$notinad = $true
		Write-Host "User " $Fullname " is not in AD.  Double check spelling, etc." -Foregroundcolor Red
		Add-Content -Path $Log -Value "$($Fullname) is not in AD.  Double check spelling, etc."
	}

	else {
		$notinad = $false
	}

	#If user is in AD check if enabled in Lync and log if enabled.
	if ($aduser.Enabled) {
		Write-Host $User.DisplayName "is already enabled in Lync, skipping."  -Foregroundcolor Yellow
		Add-Content -Path $Log -Value "$($Fullname) is already enabled in Lync."
	}		

	#User not enabled.
	else {
		Write-Host "Adding user " $User.DisplayName -Foregroundcolor Green
		Enable-CsUser -Identity $User.DisplayName -Registrarpool "lyncpoolGMRC.gmrcnt.local" -SipAddressType Emailaddress

		#Check if last command failed.  If it does, log it.
		if(!$?) {
			Add-Content -Path $Log -Value "$($Fullname) not enabled.  $(Get-Date)$($error[0])"
			continue
		}

	}

	$index++	

}

Below I have posted the quick and dirty method to bulk import a list of users from a CSV file into your Lync environment using their first and last name using the Lync Management Shell (LMS).  I say quick and dirty because it lacks a way to tell if users are already in the Lync environment as well as not having the ability to cope with users that have misspelled or changed names in the CSV file.  But it works, for the most part in a jam.

I should mention that this can be modified to cope with different user views.  For example,

  • The user’s Active Directory display name (e.g., “John Doe”)
  • The user’s SIP address (e.g., “sip:[email protected]”)
  • The user’s User Principal Name (e.g., “[email protected]”)
  • The user’s domain name and logon name, in the format domain_name\logon_name (e.g., psa\jdoe)

And here is the original code to get the users imported into your Lync environment.  Again, very rough, check the updated version if you want more features.

#Variables
$File = "C:\Lync\lyncusers.csv"

#Import CSV File
$UserArray = Import-CSV -Path $File

if ($UserArray -eq $null)
{
write-host "No Users Found in Input File" -foregroundcolor red -backgroundcolor black
exit 0
}

ForEach ($User in $UserArray) {

#Check if user is in AD
$aduser = Get-CsAdUser -Identity $User.Name | Where-Object {$_.enabled -ne "true"}

#Enable user
if($aduser -ne $()) {
Enable-CsUser -Identity $User.DisplayName -Registrarpool "lyncpoolGMRC.gmrcnt.local" -SipAddressType Emailaddress
}
}

Write-Host "Users added successfully."

The CSV file will look similar to the following (in my case, DisplayName, or First and Last name):

I’ve found this to be helpful any time I need to add more than just a few users at a time into the current environment because the GUI is so cumbersome.

Read More