Here is a collection of Technical Articles I've written over the last few years. To keep this list short, I've started sorting ideas under similar topics. For example, if you are looking for a script to dump AD account info, check under the script to dump AD groups.
If that isn't working, check out the tech cloud on the bottom of the right side-bar. I try to categorize all my articles by content, script type, etc. This should quickly limit your search from the 100+ items, to just what you are looking for.
I was just introduced to a cool new add-in for Firefox, called GooglePedia. This cool little tool splits Google's search results screen into two windows, the left side containing your search results, the right side containing a Wikipedia screen containing your search string.
If you use Firefox, then take a look, very cool! If you don't, what's wrong? Download Firefox now and get on the bandwagon. The inline spell check of web forms (like blog posts) alone is worth it.
After I got my new PC, the first thing I wanted to do was replace some of the functionality of my dynamic desktop. Primarily this meant a useful Google Search box. My search found 3 gadgets already in play, but to my dismay, they all link to adwords sponsored websites.
So, using Darren's example, I found that gadgets are really just little tiny websites. Hmm, I can code websites. Even really tiny ones.
I would like to present, my basic Google Search Gadget. No encoded text, no adwords, no fancy graphics, or crazy cool search technology. It simply provides a form to start searchs.
Future revisions:
| Attachment | Size |
|---|---|
| GoogleSearch.gadget | 4.29 KB |
Of course, you make one thing, then people come up with something better. That same guildie who is working on my robe, came back and said, "Why don't you just read the ingredients directly from Wowhead?".
OK, easy enough. Read from Wowhead, get reagents, recurse via loop. Two sources came in extremely handy for this. First WWoIT provided several excellent examples for reading from a web page, then Dan Sullivan provides this excellent XML in Powershell examples.
The final result is a bit more versatile than the last script.
Please Enter the WowHead ItemID (found in the URL)?: 42101
Ebonweave Robe x 1
Ebonweave x 8
Bolt of Imbued Frostweave x 8
Bolt of Frostweave x 16
Frostweave Cloth x 80
Infinite Dust x 16
Eternal Shadow x 16
Bolt of Imbued Frostweave x 6
Bolt of Frostweave x 12
Frostweave Cloth x 60
Infinite Dust x 12
Eternium Thread x 1
Frozen Orb x 1
So, here's the new and improved script:
My warlock has reached 80. He has just about all the regular quest rewards that one can get through soloing the area. Now comes the long haul of playing the more advanced group areas of the game, except even my best quested gear wasn't cutting it for some of the lowest heroic dungeons.
So, using a combination of MaxDPS and the Gear Wishlist, I determined that the best tailored outfit would be the Ebonweave Robe. This tailored purple item would be a great step up in the current item I have equipped.
Unfortunately for one of my guilde tailors to make this for me is going to require some serious materials "mats". Just exactly what it would require, I wasn't so sure. So, knowing this is possible via a script, I developed the following. It reads a simple list of ingredients from a CSV (attached below). It then takes the ingredients of those ingredients (Bolt of Imbued Frostweave = requires infinite dust and a bolt of frostweave, etc.). It then creates a list of the raw ingredients to make this robe.
In case your are curious, they are:
Raw materials for Ebonweave Robe
| Attachment | Size |
|---|---|
| ebonweaverobe.csv | 435 bytes |
This updated version of the code will pull down the latest image from WorldofWarcraft.com from either their Blizzard images or the new Fan Art section randomly.
Recent Updates to code:
| Attachment | Size |
|---|---|
| getWoWBkgd.zip | 1.59 KB |
Nowadays, it seems almost everyone has their own website. You can shop for your groceries, order a pizza and even buy a home all from the comforts of your arm-chair. So, why don't you have your own website all about you. I do!
What? No technical expertise? Bah. No dedicated connection to the Internet? Bah. I know, you don't have the slightest idea of where to get started. Ah! That I can help with.
Here are my very easy steps to get you running with your own website in just a couple minutes work. (The hard part comes later, when you try keeping the content fresh!)
So, there's nothing stopping you now. Get creating that new content and let the world know who you are. Leave me a comment here with a link to your site, and if I agree with your content, I'll post it here for others to review. Note: Spammers, I will just delete your comment and not look back.
I just received the latest joke/hoax/chain-mail from a family/friend/co-worker regarding some new issue, scam or sentiment. When this person forwarded along the message, I had to skim through pages upon pages of valid e-mail addresses to get to the actual message, which ended with "forward to all your family and friends".
Thanks to this person, I made $$$ with very little work. How? I extracted out all 200+ (validated and real) e-mail addresses, then forwarded the file off to a website that collects e-mail addresses. (Spammers pay extra for validated e-mail address like these, you know!!)
With a little effort, the friend/family/co-worker could have avoided the pending spam.
Working together we can help decrease the amount of spam that we all get. On the other hand, keep sending me your messages, and I'll keep making a few bucks in the process.
Now that you've been using that computer for awhile now, it is now slowing down, to a crawl, and you don't know what to do.. I've put together this short article to cover some of the basics that I check for with slow computers.
Computer slowness can often be attributed to too many applications running in memory. When you first start up Windows, it has a series of programs that automatically launch at startup. These programs add functionality to your computer, behind-the-scenes. Most are begnign like your anti-virus solution or functional like Google Desktop, but there are also programs on your computer that you might not want.
All viruses have some method of spreading themselves. Since 2000 with the ILOVEYOU virus, viruses have utilized Internet e-mail to deliver to unsuspecting recipients. A virus will attach itself to an e-mail message with friendly looking body, enticing the user to open the message. Once opened, the virus grabs their e-mail systems address list and sends a copy of itself to everyone (spoofing the FROM address on each e-mail). Inside a corporate environment, the virus may go once to everyone in the address list, then again to each of the distribution lists.
To keep from being infected, follow two simple rules. Don't open an e-mail you did not anticipate. "I never get attachments from my uncle, what is this??" and update your local virus scanner at least once a week. There is at least 10 new viruses written each week and any one of these has the potential to do harm. Only 1 each year will reach "TV News worthy".
If you think you are currently infected, check out HouseCall by Trend Micro. It can scan and clean your computer over the Internet. You will need a fairly fast Internet connection. Otherwise, download and install a desktop anti-virus solution. I've listed two in the resources section at the end of this article.
I hope this helps with your computer's slowness.
Resources:
Having recently migrated all of our department to Exchange 2007, we were excited to take advantage of the new conference room functionality! No more Outlook Resource configuration, no more faulty Auto-Accept script! Microsoft has FINALLY programmed in full-fledged resource mailbox functionality into Exchange.
Our dilemna. After migration from Exchange 2003, our resource mailboxes were showing up in the Exchange Management console as LinkedMailbox type.
Sounds easy enough.
My following code, will read a straight list of mailbox names, and convert them from LinkedMailbox type mailboxes, to RoomMailbox type, then configure it as a conference room based on the following criteria.
Sure creating a signature in Outlook is easy. Open Outlook, type in some information, change a few settings and you'll have a decent looking signature. Now, if you want to include a graphic (like a company logo), or use HTML, you have to get a bit more fancy.
That is why I developed this script. This script makes it rather easy to build a fancy signature using various colors, fonts and font sizes. In addition, I have coded functionality to include the graphic (if it is on an external webserver). To make it easier, I have even coded the script to pull information from Active Directory (thanks to a script I found). Drawback being it doesn't work if it cannot access a local domain controller. I am going to work on that. I'd like to use the script at home..
| Attachment | Size |
|---|---|
| signature.zip | 6.76 KB |
One of my first contract jobs was for a small IT company in the area. I worked with them for about 4 months before a permanent, salaried position came along. (Sorry, I like having someone else pay for the benifits) One of the most memorable things the owner shown me was his background.
Now, he was a very private person, so I don't mean his personal background. I mean the 'desktop' image that he had on his computer. It consisted of virtually hundreds of links to websites and resources that he used regularly. Over the last few years, I have attempted various methods to recreate it. It's a really easy concept, create a webpage, add links to it, and set it as your background.
That brings me to my latest script. First it reads the contents of a special folder, containing several desktop sized images. I have been enjoying the art by this artist.
(These are especially great because he has one specific to my widescreen monitor resolution 1680x1050. ) The script randomly picks one for the background. Next it reads a short CSV file on my local computer containing URLs and titles for various resources I connect to regularly. The script creates links to these resources in the HTML. (They can be several layers deep if you want too! Personally, I put similar resources on the same line (gmail, yahoo mail, etc.) The final step overwrites an existing HTML file on my computer. I run the script as part of my logoff routine, so it's available next time I logon.
Variants of this background file have included live feeds from web cameras, weather maps and even graphs of system performance. I have also added portions to this script to have it set the background to the newly created HTML file, but since it never changes, it isn't quite necessary. Since I am still using a table to layout the page, the latest revision of this script defines the left and right columns using the screen's actual width, not percentages.
| Attachment | Size |
|---|---|
| My_Background.zip | 3.96 KB |
My wife and I were recently considering the purchase of a new home in our area. We went through a million what-if scenarios about the new home, laying out the pros and cons of the house, or current place and all the financial concerns involved.
While running all the numbers, I was constantly faced with numerous calculations. Going out to a mortgage calculator wasn't always the favorable solution. That is why I worked up this Excel spreadsheet to calculate various scenarios (what if our house sold of 10% more? What if we qualified for a 45year fixed loan? what if we paid off the car? )
The attached spreadsheet is the result of that process. You will need to populate the various 'yellow' fields with:
Our final deal-breaker on this house was a suggestion from a Realtor that we trust. She suggested waiting for the local market to improve so that our house would sell for a bit more. That would help us put down a larger down payment on the new place and lower the monthly bills.
| Attachment | Size |
|---|---|
| House Payment Estimator.zip | 4.59 KB |
One thing every corporate employee has to deal with is email. Go on vacation, and you get tons of it. Stay home with a sick kid, and you get a ton more. The work does not stop, even if you can't go. In turn, we either don't take time off, even when needed, or we read our email all the time (Curse you Blackberry!).
As an IT administrator, I would get alerts. Lots of them. Backup alerts, server alerts, email slowness alerts, spam filter alerts, and even alerts that the alerts didn't work! To combat this ever growing corporate 'spam', I created a simple set of rules in Outlook to manage them.
Using Outlook's own auto-archiving functionality to clean-up messages, I was able to maintain a mailbox well within the corporate standards. The attached PDF document details how to duplicate these settings.
Note: A good portion of performance of Outlook in an Exchange environment depends on the local configuration and settings of the Outlook client. Check out this wonderful document created by a former co-worker regarding various settings Microsoft Support recommended.
It can be found here.
| Attachment | Size |
|---|---|
| Configuring Outlook AutoArchiving Options.pdf | 121.74 KB |
I had an interesting request. A user wanted to search their mailbox for all read/not read/delivery/non-delivery receipts in their mailbox. You would think that it should be as easy as searching for "READ:" in the subject line. Unfortunately, Outlook does a wild-card type search on what you enter. This means you may get read:, bread: and read:s.
What about using forms? Based on my previous Outlook-form-coding experience, I knew that Outlook used different standard forms for the various types of messages. IPM.Note for email messages, IPM.Contact for (well, gee) contacts, etc.. As long as the message didn't traffic the Internet, the default form should be used. So, what is the default form for Read Receipts??
What form? Opening up a read receipt, I checked the properties tab. Here I found that the message type was report. Cool, now I went back to my query and tried to search on the form type of "report", but when you add the form type "report" to your search query, it returns NONE as the options. Now I know that this means there are no readable fields on this form.
Final solution: Doing a quick Google search on Message Class, I determined that this was the field I needed. Common message classes are IPM.Note and IPM.Contact. So, I created a query for all messages, where the message class contains report.
My search folder returned several read receipts and an undeliverable response in my Inbox. I have not tested it with other response type messages, but believe it will find all message responses. Meeting responses will probably require a slightly different query.
During my work day, I probably send a 20-30 email messages. Each time I typically look up someone's email address, copy it to the (keyboard) buffer (CTRL+C), click on a shortcut I have to open a new email, then paste the email address into the new message. I thought, what if my new email shortcut, would test the keyboard buffer and then automatically paste the address for me?
Save the following VBS to your local computer. Drag it into your quick launch bar, then change the icon to something useful (like Outlook's new message icon)! One click new emails that will be pre-populated with the last email address you copied.
The default Outlook Address Book is saved in the Windows registry. I've created this script to be used to push down a new Address Book view at logon for a large group of users. The script will read the current default Outlook profile for the currently logged on user, then push down the address book view you specify.
To configure the script:
00,00,00,00,dc,a7,40,c8,c0,42,10,1a,b4,b9,08,00,2b,2f,e1,82,01
Const DestABUsers = "00,00,00,00,dc,a7,40,c8,c0,42,10,1a,b4,b9,08,00,2b,2f,e1,82,01"
Now, you can push it out as part of your logon scripts?? or add it to the RunOnce settings on your Windows image.
:)
| Attachment | Size |
|---|---|
| set-DefaultABView.zip | 2.42 KB |
Back when my daughter was born, we were taking pictures of everything. "What a cute smile!" (click) "Oh she is biting that toy" (click) "She's finally asleep!" (click) (click) (click) (click) (click). This ended up to be one roll of standard 35mm film each day. Two months later, we were spending more on film developing, than on diapers! We started doing research on the multitude of options. The day before my sister-in-law's wedding in June 2002, we bought a Sony digital camera.
This camera, along with a 128mb memory stick (MS) allowed us to take approximately 60 pictures at a time. During the wedding, one of us would run upstairs in the hotel, download pictures, and come back. If I remember right, we took close to 600 pictures this way. According to family members, some of our pictures turned out better than the professional photographers. :) We were able to share our pictures out on Ofoto, and anyone could view them within a few days after the wedding. (The photographer took almost 2 months.) Plus, they could order copies for themselves, and we did not have to pay for the processing!!
Now 3 years later, we still have that camera, and have invested in second, smaller Sony camera (DSC-W5). This camera, has 32mb on-board and can use the Sony PRO Memory Sticks! With our 4GB PRO memory stick, we can take 1,660 (5 megapixel) pictures on a single outing! We never transfered pictures to the laptop the entire 8-days in Maui (over 750 pictures and videos). Additionally, the camera and 4Gb MS allow us to record up to 3 hours of continuous DVD quality video! No longer need to bring along our bulky Mini-DV video camera either!!
Unfortunately with digital cameras there are a number of technical considerations. If my computer where I am storing all the images dies, catches fire, or is stolen, I will lose 3 years of pictures. Also, with the simplicity of taking pictures and considering the low cost of viewing them, we now take multiples of each image (horizontal, vertical, with smiles, with a pose, candid, standing in front of the car, behind the car, etc.). In essence, there is virtually no limitations to how many pictures we can take on a single outing.
Technically, what does all this mean?
To use the attached file, you will need a unZIPing program like WinZip or 7-Zip. Open the file and extract the two files to your My Pictures folder. I'd suggest creating a shortcut on your desktop. (Hold down right-mouse button, drag to your desktop, release file and select "Create Shortcut".)
Copy and paste the following code into a file called MoveFiles.BAT. You will need to edit the script to reference the drive your memory stick connects to. Change the line Set MyMS= to point to your drive.
The attached VBScript is a work in progress. It needs a file set up on your removable media to read from. Then you can run the script to move files either direction. I use the same script to move MP3s onto my SD Ram chip.
| Attachment | Size |
|---|---|
| Removable Media Synchronizer2.zip | 5.82 KB |
I was just reading through another news article about the fires in Southern California. The article was discussing the displaced families that were returning home for the first time. The focus family found that they had unfortunately returned to a burnt out shell of a home.

Among the possessions the a 56-year-old photographer lost were his transparencies, melted inside a fire-resistant box, and a photograph of his father.
"I've lost my history," Sanders said. "All the work I've done for the past 30 years, it's all destroyed."
- Yahoo News
This got me thinking. First, my computer has every digital picture (over 5 years and 20gb) ever taken of my kids on the hard drive. Secondly, a fire-safe box is not going to protect a stack of DVDs. What if my house burnt down while I was at work. I have visions of heroically racing into the den, grabbing my PC and running out of the house, but it is unlikely that my house will be burning while I am at home. "Hey, what's that burnning smell and why are the fire alarms going off? I am not cooking..."
Digital Disaster Recovery for the Home. With this, I have been implementing a backup methodology similar to those implemented in a corporate environment. This includes backing up all my digital files to removable media then shipping them to relatives. I currently have two stacks of 8 DVDs with 4GB of pictures and videos on each. Approximately every 2 months, I create 2 new DVDs containing the new pictures taken (one for me, one for off-site).
Next steps? A digital inventory of the house. As I stated earlier, digital images are virtually free to take and easy to keep. I plan to start taking pictures of household items, and their serials. I plan on starting with the electronic items (like the TV, TiVo, and digital camera). Then take pictures of the kitchen table and chairs (all wood), the bedroom set (also wood), the sofa and love seat, and well just about everything.
Insurance will cover replacing the material items. I can buy myself a new computer, stock full of all the applications I use. Unfortunately, there is no amount of money that can replace the happy moments we've recorded.
In the last 10 years, email has evolved from the uber-geeky tool into the corporate mainstream solution that no one can live without. At the base, Internet email is a 40+ year old technology that was originally designed to provide a reliable (not time sensitive) solution for communications between colleagues. As it has gained popularity corporations have started to rely on it for business critical communications with their customers and vendors. Nowadays, IT departments learn about their outages by how well the email solution is performing.
In the rest of this article, I plan on covering a few of the troubleshooting techniques I use to resolve Internet email issues and what may have caused them.
The Parts of an Email
Every email message delivered across the Internet has 2 basic parts, a header and data. The header consists of the delivery information (To, From) and routing information (what servers processed the message when). The data portion consists of the subject, message body and any attachments. (Note: Since Internet email cannot directly handle files, these attachments are [w:uuencoding|converted] to text and placed inline with the message body. This encoding process can add an additional 30% to the attachment size when completed.)
Message Delivery
The delivery of an email message is not obvious. A message may bounce around a dozen times (or more) before it is delivered to the intended recipient. This entire transaction can be found in the message headers.
Here is a great graphic from Wikipedia:

If you read the header from bottom to top, you see that Alice sent the message at 16:56 -5hrs (or EST) (line #7) and it was delivered at 13:55 -8hrs (or PST) (line #2), meaning it officially delivered before it was sent! (or the two email servers are using different time synchronization servers. You'll also notice that this header includes the IP Address of the servers it touched (line 2 & 4). This is helpful when trying to troubleshoot errors later on.
Here are the possible SMTP Response codes that you may see. Please keep in mind that in general a 2XX indicates success, a 3XX indicates that the server has understood the request but requires further information to complete it, a 4XX error is temporary and a 5XX error is fatal. Float over the
for my take on the error.
| SMTP Code | SMTP / ESMTP Message Description |
|---|---|
| 211 | System status, or system help reply |
| 214 | Help message |
220![]() |
Service ready |
| 221 | Service closing transmission channel |
250![]() |
Requested mail action okay, completed |
251![]() |
User not local; will forward to (other address) |
354![]() |
Start mail input; end with . |
421![]() |
Service not available, closing transmission channel |
450![]() |
Requested mail action not taken: mailbox unavailable |
451![]() |
Requested action aborted: local error in processing |
452![]() |
Requested action not taken: insufficient system storage |
500![]() |
Syntax error, command unrecognized |
501![]() |
Syntax error in parameters or arguments |
502![]() |
Command not implemented |
503![]() |
Bad sequence of commands |
504![]() |
Command parameter not implemented |
550![]() |
Requested action not taken: mailbox unavailable |
551![]() |
User not local; please try |
552![]() |
Requested mail action aborted: exceeded storage allocation |
553![]() |
Requested action not taken: mailbox name not allowed |
554![]() |
Transaction failed |
One of my peer departments is working on spamming the corporation. This internal spam, aka Corporate Newsletter, is to go out to everyone with a mailbox in the corporation. Unfortunately, a number of these people have abused their rights and their mailboxes are limited to receiving e-mail from only their managers.
In Exchange 5.5, you could create a simple CSV file and run the Admin tool to gather this information. Unfortunately, in Exchange 2003, mailbox settings are now integrated into Active Directory (AD). AD maintains all the mailbox information and settings, whereas the Exchange Admin tool is simply for server management (mail routing and global limits, etc.).
Then, how do you gather this information? I being the lazy, programmer-at-heart, that I am, wrote a VBScript to export the information. This worked great as I could set variables in the script to export the information I needed. This only worked for about a month, as I wanted pass this tool along to the internal employee for use (no way I was going to run this each time someone new was hired!!). That's why I put an HTA front-end on it!
To Use The Script
Select Case statement to include each of the OU's.
NOTE: We have set Custom Attribute 1 (aka ExtensionAttribute1) to a value (1, 2 or 3) for group or resource mailboxes. For example, the Postmaster mailbox has a value of 1,Conference rooms have a value of 2. Line 121 of the code is designed to filter on these values. Remove the line completely to get all mailboxes, or modify it for your environment.
Update August 16, 2007: I've modified the code to query the local AD for it's structure, so the above modifications are not necessary. After I made the changes, it started timing out when running the query, which shouldn't be related to the script changes. I suspect slowness in my AD.
| Attachment | Size |
|---|---|
| User Export Report.zip | 3.72 KB |
| User Export Report 2.zip | 4.7 KB |
The company I am working for has a slightly different security model than I've seen before. It is probably because the largest Exchange server I've supported previously only had 3,000 mailboxes. This one supports 10x that number, with plans to grow to over 100,000 mailboxes by this time next year.
With that, they use a seperate "security" domain for logon and authentication than the "resource" domain where their mailboxes reside. This means that the account you logon to your computer, may not be the same account you read your email from. That account will need to be granted secondary permissions to that mailbox, aka "Associated Exernal Account".
Along that same strain, you can no longer simply assign permissions to a user via the Managed By tab. Their mailbox is assigned permissions, but you need to grant their security account permissions also if the group owner wants to add/remove members.
That's why I developed this script. This script will assign Manager permissions to a distribution list. It assigns the selected name rights on the Managed By tab, then assigns the "Send As" and "Write Members" permissions on the Security tab to the selected user's Associated External Account.
There are a few limitations/warnings:
I've cleaned up the code, so it no longer asks for a specific OU. It will query your entire domain for the specified DL. To run, double-click on the downloaded HTA and have fun!
Note: I have recently (3/26) updated this script to filter on the entries, instead of search each one. This makes the overall process rather quick.
Update (6/6/2008): I have added code to allow you to remove people from the security settings on a DL also. Currently working on an issue that generates an error when dealing with an apostrophe in the distinguished name (for example ldap://cn=Eric's Big List,ou=groups,ou=ericwoodford,ou=local). VBScript is taking it as the end of string and breaking..
| Attachment | Size |
|---|---|
| SetNewDLManager.hta | 18.81 KB |
This HTA applet allows you to grant extended AD permissions to a specific user. I use it to assign permissions to the Associated External Account of an AD user rights to modify their own delegates.
I found what values I needed by configuring a single user with permissions, then using Richard's DACL export script to dump that user. I then modify the script (see line 248) to match the permissions I want to grant.
The applet runs faster on the DC, but is usable on my local workstation.
| Attachment | Size |
|---|---|
| SetDelegatePerms.hta | 12.8 KB |
Today I had the honor of working with a company after a catastrophic failure of their Exchange server. One day their hardware was working just fine, the next the server will no longer boot and Exchange is down.
As part of the repair, I installed Exchange 2000 on a new server, and attempted to mount the databases from the mirrored drive. After a few manual uninstalls of Exchange and the the typical passes with ESEUTIL to repair the dirty shutdown the database was coming up clean, but still would not mount.
Checking the Application event log, I found that the server was built in the wrong Exchange Organization. Ugh! As Microsoft states repeatedly, to change the Org, one must reinstall Exchange. In Exchange 5.5 it was so bad, that we would worry about the case of the Organization name when adding new servers to an Exchange site.
That was COMPANY and not Company for the Organization name, right??
In 2000 and 2003, I've always understood that this had not changed. Plan ahead and do it right the first time. So, I started an uninstall of Exchange 2000 off this client's server while scouring Technet and Google for a better solution. Of course, as soon as I started the uninstall, I found that Exchange will NOT uninstall because it sees mailboxes are still on the server. Despite not successfully mounting, it must have partially mounted the database and Exchange now thinks they are on the server.
Using the Manual uninstall procedure again, I remove Exchange one more time, do another reinstall, but this time it also fails. Exchange never asked me to change the Organization as it is still registered in AD. Oh well. That's when I found this tool. LegacyDN.
Like RegEdit, this tool has tons of disclaimers:
Never use [name of tool] on a production database, never use unless you have backups, never use on unless you have PSS on hold on the phone and we tell you to run it..
So, I closed my eyes, crossed my fingers and double clicked on it. By default it comes up in read-only mode. I immediately see that it found the First Administrative Group on the server. Clicking on the fields do nothing, but I can see I have hope. So I close it, and reopen it in /FORCEWRITE mode. Click and the Organization field populates. I replace the text with the correct entry, click Update, wait 30 seconds and "The Organization has been updated successfully.". I imagine that my 30 second wait was in part to only having 8 mailboxes in this information store. If this had been a store with a couple hundred or thousand mailboxes, this process may have taken much longer.
Now the database mounted successfully and all is happy. The users can send and receive email without issue. Next, migrate them to Exchange 2003...
Some useful references.
When running through the latest version of the Exchange calendar update process, it has you assign permissions to all mailboxes on the server. To modify all the mailboxes, you need to provide a list of distinguished names (DN) for each mailbox. Unfortunately this is not simply the DistiguishedName field that you would query from AD, but the LegacyDN entry. You need to query the Exchange environment to get this information.
The following script, I pulled from various sources (primarily my Advanced VBScript book off my desk). It echos the DN to the screen, and also creates a CSV file in the folder it was run from. I did have to run it from the Exchange server, but it may also run from a workstation running the Exchange system admin tools.
In my environment, I am always looking up a user's email address, or trying to find out what Exchange server their mailbox is on. That's why I developed the attached script.
It will do a wild-card search against your currently logged on domain to find any account with those values. It searches the Displayname, proxyaddresses and mail fields.
| Attachment | Size |
|---|---|
| FindEmail.zip | 7.03 KB |
Scenario: I was given a list of 15,000 email addresses and asked if they were still valid in our Exchange environment.
Easy method: I ran a simple VBScript that does an LDAP query against each email address. This worked great, except that it took close to 5 seconds per email address to query our environment. (~20 hrs!) The over-all run time was going to be too extreme.
Next method: Read all entries into a datalist using the tricks from Microsoft Scripting Guys. The script would read each object (primary;proxy) into seperate records, then search each one. This ran for 2 hours before the server logged me off. Even if I deleted entries that I found, it still took too long.
Final method: Read each email address and append it to a string for each letter (for example "administrator@example.com;author@example.com" went in A) accessible via an array. Now I have a 50ish (a..z,0..9,!#$%^) row array containing unsorted lists. The script just needs to find the correct row, and see if the email address exists there.
The entire process took approximately 14-15 minutes. This inclides 12 minutes to read in all 250k email addresses from Active Directory(AD) and then sort them. Processing it creates a NEW csv containing the original line, then appends TRUE or FALSE. If it finds the email address, it puts a TRUE, otherwise it puts FALSE. It does very little clean-up of the email addresses it reads from the CSV, but that could be improved rather easily.
| Attachment | Size |
|---|---|
| Find_Duplicates_in_File_v2.zip | 2.64 KB |
We recently finished a project updating the naming standard for all our Windows AD accounts. Once completed, I found that approximately 3% of the accounts had the alias field set to this old naming standard. Googled high-and-low, I could not find a simple script to set the alias field. So...
This script reads a text file of account distinguished names, then modifies the mailbox alias (aka mailnickname) field to match the SAMAccountName field. Added protection for accounts without mailboxes associated with them. Found that by setting a mailnickname, mail-enabled the account.
Attending a class this week for Exchange 2007. The question came up to export all SMTP email addresses for all mailboxes. In the lab environment, I worked up this script.
I have not tested this in a production environment, so I am not sure what will display for users with other than SMTP email addresses.
The migration process used to move a number of mailboxes created a couple hundred dead mailboxes objects in our environment. Their mailbox information needed to be cleared before their mailboxes could be migrated to the server for the final time. To fix this, I looked into a script. First I found the script at TelnetPort25, here. This script goes through the entire environment and purges all deleted and non-system mailboxes. This would work great, but querying an environment with literally thousands of mailboxes is a daunting task.
That's when I found this script that would simply dump all the deleted-not-purged mailboxes on a specific server. Running this script generates a CSV file with their displayname, and some additional information. I copied the displayname field out of Glen's script and pasted to a text file to use and re-wrote Telnet's to fit my purpose.
Note: uncomment the line ' objExchange_Mailbox.Purge when you feel the script is working correctly.
Here is a small HTA applet that I have built to export the membership of various groups in Windows Active Directory. It provides some basic filtering (owner, specific OU, name contains), plus 3 modes of export, XLS, CSV, or HTML to screen. Beware, if you have office 2007, XLS is XLSX format.
To run this in your environment, it will need to be modified:
line 27 & 28
line 55 & 56
CSV mode gives the best detail as XLS has a 255 character limit on single fields.
Just fixed issue where it required you to pick a subOU in order to continue.
| Attachment | Size |
|---|---|
| DL Export Report.zip | 6.3 KB |
Friend is working on the dirty deed of removing a series of accounts from AD. As part of that clean-up he is to find all the distribution lists that each account is assigned manager on. Using the Quest ActiveRoles Powershell tools, you can quickly find these unfortunate people using:
I am working on a project to recover 30 individual days of email from a clients mailbox. This requires me to restore 30 days worth of backups to the Recovery Storage Group(RSG) on a specific server. I have quickly grown tired of selecting the name from the giant Exmerge list and worked out how to use a batch file to run Exmerge against the RSG.
Part 1: Exmerge.ini
Part 2: database.txt
Part 3: mailboxes.txt
Part 4: the Batch file (exportMbx.bat)
I've now put a shortcut to the bat file on my desktop and double-click it after the restore completes. If I could only find a script that would then dismount the database, mark it for overwrite and start a new restore from the server, I'd be done! Unfortunately, I've been told by Microsoft you can't script against the RSG, so still got a bunch of clicks for each day.
Back to work...
I needed a quick script to create a series of distribution lists on an Exchange environment. I thought, "Cool, a chance to flex my PowerShell muscles!" From that I found new-qadgroup from the quest tools set and new-distributiongroup from the Exchange tools. After quite a bit of muddling around, I was never able to recreate my script.
Requirements I was trying to meet:
import-csv)| %{new-distributiongroup -name $_.name}Unfortunately, after working on the first 3-4 items, I was stumped. VBScript failed me on a number of these, just in the fact that it's not widely published and a few answers varied. So, here is what I developed. The script fails when adding more than 1 additional proxy address, otherwise it worked for all my other tests.
(Sorry for the wrappage..)
When decommisioning an older server in the environment, it is essential that all the former services are moved off it. This includes the existing applications (including databases), file shares and printer shares. Unfortunately there is no easy way to capture who is mapped to each of the pritner shares. Outside simply monitoring printer traffic, or visiting each desktop, Windows (AFIK) has no method of tracking this.
Hence another script. This script queries the active computer for all printers, then exports the 'resource name' (port) and share name to a CSV in a specific location.
| Attachment | Size |
|---|---|
| enum printers.zip | 699 bytes |
Expanding on my code to query single printer information, I found I could pull all networked printers from Active Directory(AD). This will help in cleaning up the naming standard for all our printers. Hopefully making DNS cleaner by using a single standard for host(A) records. Final file is written to c:\printer-info.csv. The attached script will return the following:
To get the script to run, you will need to modify this line (#19) to match your current environment.
Sources: Microsoft, Microsoft, and Geek Speak
| Attachment | Size |
|---|---|
| EnumPrinters.vbs_.txt | 6.87 KB |
My wife is a seventh grade science teacher. One of the many difficulties she has to deal with, especially on large written projects is student plagiarism. The Internet is just too tempting for some students to avoid. Here they have searched and found the perfect article that answers all the questions that the project asks of them. Why not just print it out and turn it in??
Fortunately for seventh graders, school does not expell kids for plagiarism, they simply have to do the project over again or take a zero on the assignment. Unfortunately for the students, their plagiarism is typically very easy to spot. Not many 12 year olds can typically write at the same level of a college graduate (who would typically be publishing papers on scientists, or science topics). This makes locating sources of plagiarism very easy to locate.
How?
Take the typical class project, a report on a famous scientist and pull segments of phrases that the student used.
Take for example this segment:
Benjamin Franklin
Franklin was a prodigious inventor. Among his many creations were the lightning rod, the harmonica, the Franklin stove, bifocal glasses, and the flexible urinary catheter. Although Franklin never patented any of his own inventions, he was a supporter of the rights of inventors and authors and was responsible for inserting into the United States Constitution the provision for limited-term patents and copyrights. My source..
When reading a paragraph like this on a student's report, a red flag often goes up when they use phrases like Franklin was a prodigious inventor or uses words like "among" or "although". (If not plagiarisd, it is likely Mom or Dad wrote it.)
Using Google
In the search field of Google, I do an explicit search for the scientist's name.
Now, I try by adding a phrase from their assignment.
From here, 5 sources are not that difficult to follow-up on. Typically, you can find the student's source within a few hits. Print out their source, staple it to the assignment, then mark it with a 0! OOOO What fun!!
4 years ago I invested in my first MP3 player. I purchased online a 1GB micro-drive player from RIO. This device was perfect for what I needed. I could load up 100+ songs on the device and listen to commercial-free music where ever I went.
Early last year, that microdrive quit working. I guess dropping it on the ground a few times was a really bad idea. This was unfortunate, because I found several authors had started podcasting their books for free. Now I had a better understanding of what I wanted in a player.
For a replacement, I had these requirements:
Based on this criteria, I started shopping. I checked Target, Wal-Mart and Best Buy to see what was available. I found that seldom do MP3 manufacturers advertise 'bookmark' functionality on their devices (like the RCA Lyra). As this was key to my search, I went to searching on the web for brands sold locally.
Personally, I like using PriceGrabber.com for their search, and review options. I can filter down all my options in one search field and get the best reviewed products. Plus they often have links to sites with free shipping!! (Almost as good as buying it locally!).
Decision Time
I ended up purchasing another RIO device. I knew the RIO devices had the bookmark functionality, plus the Forge 256mb Sport, has a SD memory slot. I also loved the idea that it used standard AAA batteries, so I wouldn't need to purchase a separate charger for my car. I did purchase a bunch of rechargable AAA batteries and so far, the device has performed wonderfully. I download files to my laptop, use the internal SD slot to put them on the SD chip, then listen!
As you may already know, I use my MP3 player simply to play audio-books (aka podcasts) while commuting to work.
I use Juice (fka iPodder) to capture these files. It does an excellent job of downloading content and placing it on my machine. Once downloaded, I drag and drop the files to my MP3 player.
Unfortunately, my cheap ($5) MP3 player (Sansa 100?) sorts files using an odd technique. It appears to sort them by track number, then title. So if I have 2 active stories on my player, it will play track 1 - story 1, then track 1 - story 2, track 2 - story 1, etc. I think this is because sometimes the track number is a 'string' value?? To fix this, I cleanup the ID3 tags values.
This script utilizes the CDDBControl (from Roxio) to get access to the ID3 tags. If you have a Roxio product installed, you may already have this file. Otherwise, I've downloaded it from here. Register it like you would any new DLL on your computer.
Inside Juice, I setup an advanced option to call this script when a download finished. Cool? Go into Juice, select File, then Preferences, and click on the Advanced tab. Click the checkbox for Run this command after each download, then put in a fully qualified path to the script. Mine is:
You see a short popup each time a file finished downloading and the script runs. The Title name changes to the first two characters of the name(track number) - Full name of podcast.
For example (for the Max Quick Part 2):
Title before = PB-Max Quick 2: Two Travelers - Episode 1
Title after = MA01-Max Quick 2: Two Travelers
In recent months, I have noticed quite a few new local wireless hot-spots appeared in my neighborhood. These hots-spots are my neighbors (within 1000 feet of my house), who are using the out-of-the-box configuration and no security measures. This means anyone driving by my house can access the Internet while sitting in their car (war driving).
Using a free tool (Netstumbler), I can gather information about all my neighbor's wireless routers, including name and encryption settings.
Now that I know their router settings, I can become a member of their network. In addition to using their connection to the Internet for free, I could connect to shared network resources, like printers, and shared drives. Additionally, since they haven't enabled encryption on their router, they probably haven't changed the router's admin account password.
With little effort, I logon to their router, and check the DHCP table for a list of currently active devices, including computer names and IP addresses. I can try PINGing the IP address and see if it responds. If it responds, I can try mapping a drive to the default admin shares like C$ or browse the computer by simply typing in the IP address in the Windows START - RUN line, "\\192.168.1.100", and see what comes up. By default, Windows will have a "Shared Doc" folder available, but sometimes you will also see a printer listed here.
What can you do about it?
Like security for your automobile, doing the basics of locking the doors and closing the windows is enough to deter most (wireless) thieves. They can always simply travel next door and find a much easier target. With the security now configured on your wireless router, you should be able to easily move your wireless devices between home, work and the coffee shop wireless networks with very little difficulties.
I was recently tasked with the process of setting up a fairly automated report to display each time one of our Executive Management Team's mailboxes had been accessed by internal users.
We had already turned on the log generation on the server according to the Microsoft tech article 867640. This generates a 1016 event in the server's application log each time a mailbox is accessed.
According to MS this includes:
In addition to malicious intent, each time someone books a meeting with another person, a backup is ran that uses a MAPI connection, or services like Blackberry Enterprise Server, accesses a mailbox they will also be annotated in the app logs. Plus, this report is destined for Sr. Management, so sending a dump of the Application logs was out of the question.
LogParser should already be your best friend. You can use this versatile tool to query any ASCII log file or server Event logs to pull out information.
Setup
The attached batch file, runs a logparser query against a mailbox server and generates a SUMMARY.CSV file.
Details
We run this batch 6 times a day (using a Windows Scheduled task), creating a 1kb file for the 20 something Executives we monitor. After a month, I have almost 1mb of log files. The script is designed to pull information only from the last time it ran, so no overlap. This batch creates a new file with updates since the last run, then rebuilds the SUMMARY.CSV file.
The summary contains the display name of the executive, date of mailbox access, the domain account that accessed the mailbox, and how many times on that day.
I've expanded this by exporting all active mailboxes in the domain (see HTA coming soon) and import that into an Access database. I then created a 'linked table' connection to the CSV. Using a simple query to correlate the domain account, to a display name from Active Directory. (I only need to update the AD Export, when a account does not resolve correctly in the query.) Then I use Crystal Reports, pulling from the Access Query, to filter the information, generate summaries, etc.
Future
To expand upon this, we've considered porting the data collected to a SQL server (which Logparser handles nicely). Until then I have a simple query I can run anytime, and get relatively up-to-date access reports for these users.
| Attachment | Size |
|---|---|
| Executive_MBX_Access.zip | 1.69 KB |
We are working to decommission our existing Exchange 5.5 environment and looking to migrate all services to Exchange 2003. As part of the decom, we need to re-direct the Internal SMTP traffic off our Exchange 5.5 bridgeheads. This meant, determining which servers were connecting to the server. First we changed all MX records in our DNS to point to the new server. Then we watched the Application logs on the server for MSExchangeIMC - ID: 2000 events.
This provided some 2,000 hits on our server. Ouch! Using LogParser from Microsoft, I was able to generate a quick query to pull the information.
| Server | Hits |
|---|---|
| citrixserver.example.local | 373 |
| othersmtpserver.example.local | 214 |
| appserver.example.local.local | 150 |
| 192.168.0.28 | 25 |
| webserver.example.local | 1 |
With this data, I was able to contact the server owners and have them change their relay information.
This query runs in about 20 seconds on 2 servers with 3 days of data. Putting this into a BATCH file, I was able to make the script rather user friendly.
| Attachment | Size |
|---|---|
| WebCalendarHTML.zip | 10.38 KB |
| ConferenceRoomWebsite.zip | 7.93 KB |
| settings.txt | 831 bytes |
Microsoft has an Auto-Accept Agent (or AAA) that can be used on Exchange 2003 servers to process incoming meeting requests to resource mailboxes. Simply send the resource an invitation and within 10-30 seconds, the room will respond back with an acceptance or denial of your request.
For the last 2 months we've been using this script to process the 61 various resources in the environment (conference rooms, laptops and LCD projectors). Combine that with my own home-brewed calendar export script, the company has a complete resource tool for virtually all items in the environment. Unfortunately over the last few weeks, we've had new issues.
Corrupted CDO Free/Busy Cache: First we had users reporting getting declined responses when the calendar shown free, and canceled meetings were still showing as busy. Why? My best results were pulled from a technical article (kb886760). Now, if you read this article VERY closely, pay attention to:
Hotfix installation information
After users apply this hotfix, they may have to wait until the end of the month before they stop experiencing the symptoms that are described in the ""Symptoms"" section. This is because the EXCDO component keeps free/busy information cached until the last day of the month. The free/busy cache is rebuilt on the first day of the month.
GREAT!! So end-users will need to wait until the end of the month to view the correct free/busy information on our resource calendars as the CDO free/busy cache is only completely rebuilt once a month. There has to be a better way...
After talking with Microsoft PS Support, I got this answer..
Notes
I needed to touch every mailbox, so it was (going to be) quite a tedious task of creating a profile and opening each mailbox. Luckily, I do have a script also for that.
Alright, that problem solved. On to the next one..
Faulty Replication: At the same time the free/busy information was not replicating, users were reporting other issues with the calendars. This fix was applied 891509.
Unplanned for behavior: OK, patched and meetings are processing. Now meetings are booking, and the calendars look really good. What do we find out? That the, wait, really, you won't believe it. Meeting requests booked on the calendar as FREE, are actually booked on the calendar as FREE. Hu? What? Users can successfully book the conference room, get an acceptance back from the room and still be booked over by other requesters who book the room as "tentative", "BUSY" or "Out of Office".
According to our Microsoft TAM, this functionality is by design.
A customer requested functionality to send a 'free' request to resources to get a accepted/denied response back, then the end-user would use other means to officially book the room.
So, now we are in the uncomfortable place of telling our users that the conference rooms will accept your meeting request marked "FREE" and very likely you will get booked over. (Don't change it to FREE later on either, it has the same effect.) I still wish we went with SWINC's product Exchange Resource Manager or ERM as it was fully configurable. it would have accepted those "FREE" requests and converted them to "BUSY" with a simple click of a check box.
So much for saving $$!
Thanks to a recent change, Americans will soon be getting more daylight. Yes, we will start saving daylight approximately 3 weeks earlier this year. Previously, Daylight Savings started the first Sunday in April, now it will be the second Sunday in March!
What does that mean for IT? Nothing, and a bunch. First Outlook bases DST calculations on the local operating systems settings. So, if you book a meeting at 10AM PST after March 11th, 2007, it will actually be an hour off. Why? The calendar stores it stores it in Greenwhich Mean Time (GMT). (10AM + 8hrs for GMT = 6PM). When in actuallity (because it's after DST starts), that meeting should be on the calendar for 5PM GMT. In addition, all applications that use straight CDO will have issues (like my script and Blackberry servers).
Nicely, Microsoft has provideed a web page specifically addressing these issues. (see here)
To fix my HTML Generating Script, search for these two functions Function GetDSTStartDate(llevel) and Function GetDSTEndDate(llevel) and replace it with this code:
Hopefully, we all get to enjoy a bit more of this saved up daylight by playing outside. I declare from this date forward that 3PM is beginning of recess. Now just need to decide what time zone that's in....
We are working on a security review of our Exchange environment. Part of that is to review who has permissions to access what mailboxes.
That's why I put together this little script. Using the Exchange 2007 Management shell, it reads our Exchange 2003 and 2007 environments, processing all the mailboxes. It outputs a single CSV file containing each instance where someone else (not SELF and not a SID) has permissions to a mailbox.
The heart of the script is this line of code. It is the one-liner that reads the mailbox information and filters on the rights I wanted. Without the -and and -notlike operators, I would need to filter through all of the various account permissions.
Note: It will prompt for the OU of the folder you want. If you don't specify anything and simply hit ENTER, it will use the root of your currently logged on domain.
| Attachment | Size |
|---|---|
| EnumSendAsRights.ps1 | 2.17 KB |
Takes a CSV file, reads headers and creates mailbox based on values.
Requires two columns in CSV, UserPrincipalname and Name. The UPN can be the SAMAccount value renamed. It will append the variable $UPNDomain to end.
Also requires both Quest ActiveRoles PowerShell tools (to create AD Account) and Exchange 2007 Management tools to set mailbox quota limits.
At my current employer, we are constantly bringing on new customers. As I detailed in my VBScript version, it's a fairly complex environment.
The attached Powershell script does the following:
Requirements:
| Attachment | Size |
|---|---|
| Create-DLsFromCSV.zip | 2.1 KB |
Invariably, when you let your local admins create mailboxes using a web interface, you will get some odd settings.
One of things that I've noticed, when running PowerShelll queries, is all the mailboxes with incorrect quota settings. Users with Send Receive limits lower than the Notification settings. Tired of these alerts, I created the following to dump those mailboxes to a CSV.
I am hoping that someone might be able to develop a better filter statement. When I tried to use:
Now.. Send the CSV to my remote admins, and ask them to help out their users.
:)
We maintain an Exchange EDGE server on our perimeter as SMTP relay. Application servers can use this server to relay email out (to internal recipients or the Internet). To keep this server from being an open relay, we maintain a list of valid IP addresses that can relay through this server. To update the the relay, we run my script below to import the IPs. On our first attempt, we found that MS Edge 2007 - Receive Connectors have a limit on allowed RemoteIPRanges values. After approximately 1100 individual IPs, it would quit accepting any additional IP addresses. Unfortunately, we have over 1300 current application servers running currently.
Dealing with Receive Connector limits. This field accepts 3 different formats: straight IP, IP Range (0.0.0.0 - 0.0.0.1) and CIDR format (0.0.0.0/24). Since I am working from a list of allowed IP addresses, the first option is easy. CIDR format requires a bit of fiddling, as you want valid ranges and using defining a valid subnet mask is complicated. So, why not use ranges.
What my script does:
Drawback is that if someone manually adds an IP directly to the server, it will be lost. Currently the script deletes any values already there.
I hadn't fully realized the power and simplicty of PowerShell until recently. My manager had asked if a script could be written that would take a CSV file of mailbox names, and hide them or unhide them. My co-worker, well-versed in VBScript, generated a 220 line solution that did just that. When I got into the office, I took that as an invitation to flex the PowerShell
Here is my code:
Some nifty points:
Note: This script utilizes the Exchange 2007 Management Shell, so you'll need to run this from a box with Exchange 2007 System Management tools on it. It does work with Exch2003 mailboxes.
Why such a difference? PowerShell has built-in functions that complete many of the basic tasks that you commonly need to do. For example the code:
I know, the code is much more complicated than necessary for my initial project. It just goes to show how much more efficient PowerShell is for scripting. In VBScript, I would have likely done all my processing inside the file reading loop and never populated the array. My script would have been more tightly focused to that single purpose.
As I learn more about PowerShell, I become more, and more, fond of it. The versatility and simplicity are quickly winning me over and I find myself writing more PS scripts.
I have been tasked with writting a script to analyze our servers on a daily basis. I found this most excellent server inventory script that pulls virtually every conceivable value from a server.
Now, on our Exchange cluster, we've used Volume Mount Points for the resources. This means that a 9gb drive with eight 330gb folders (or mount points) to SAN storage. If I simply pull the drive freespace, I get ~6gb (local hard drive), even though the mount points each show over 100gb free.
So.. this script. It queries the server ($ServerName) and looks up all the mount points, then queries the volumes and returns the current size, free space, and % free for each labeled mount point.
Note (Nov 10, 2008): I cleaned up a warning in the script that popped up a false error when the folder was empty. In addition, I realized the data is more useful to me in a record format, so I have the data returned in an array instead of simple string (CSV) format. Powershell displays the data for one server like this:
| Name | FileSize | FreeSpace | PercFree |
|---|---|---|---|
| I:\SG1\ | 229641617408 | 128873562112 | 36 % |
| I:\Utility\ | 0 | 347809751040 | 100 % |
| I:\SMTPMTA\ | 0 | 53606744064 | 100 % |
This uses the Powershell filter to limit the list of ALL DLs to only those locked down to individuals. It doesn't filter on lists that the client is a member of having permissions. I specifically was looking for mail enabled contacts having permissions on my DLs.
Returns the names of all DLs.
I am working on a project to add members to a series of distribution lists. These lists are nested into various parent lists, sometimes 2-3 layers deep. It's never been updated, but almost all these distribution groups are Mail-enabled Global Security groups. Powershell really, really wants to work with Universal groups. You can't just convert the current DL to Universal, it's parent needs to be Universal also.
The following function recurses a DL's parents and converts them all to Universal DLs using Quest's Set-QADGroup.
This PowerShell script replicates the basic functionality of my Exchange Mailbox export HTA script. Rather quickly, it exports the following values (for all accounts with an email address) :
To run this script, you will need to download and install the latest Quest tools. If you would like to include or change the fields (GivenName, employeeID, etc.) it pulls, don't expect to pull all the user properties as defined by:
I have recently revised this script that exports a few more fields from specific OUs.
A friend is working on a script to pull active LCS accounts from his AD. One last bit of information that he that was troubling him was enabled/disabled AD accounts.
Reading the Scripting Guys article, I found a switch that will tell all disabled AD accounts. Perfect, but just the opposite of what he wanted. Reading deeper, they state that when the bit is set to 2, it shows disabled accounts, so I implied that when it's set to (something else??) 0 (or 1) it must be enabled. Tested 1, nope. Then I found this article that shown that using a NOT statement will return what I was looking for.
This tiny script will query your current AD environment and return all ENABLED accounts in the environment.
The "-includeallproperties" switch is required, otherwise you will get all accounts, and not those that apply to the LDAP filter.
Note, if you haven't already done so, you'll need to download and configure the Quest ActiveRoles Management Shell to run this query. This article helped me setup my environment and includes links to the various tools I use.
Troubleshooting Outlook delegate permissions is a pain. I found the easiest way to get a user's delegates is to create a profile, open their mailbox and check each person.
That's why I created this script. Using the Quest Powershell addons for AD, it reads the delegate permissions for a specified mailbox, then looks up the display name for each delegate or mailbox they are a delegate for.
I'd like to clean up the results a little more, but for now this works nicely.
| Attachment | Size |
|---|---|
| EnumerateDelegates.ps1 | 848 bytes |
I have been attempting to do some cleanup of the Active Directory environment. My latest endeavor is to capture the last logon time from AD and correlate it to active accounts. If they're not logging on, maybe they don't know how, or don't need a mailbox??
My script here, will query all the Exchange servers for user display name and last logon time (LastLogonTime). Since the last logon is a 64-bit integer, you need to do some special handling of it. I found a number of tricks that used bit-level handling to convert the value to a date-time format, but after some pointing and nudging, I realized the simplicity of simply pulling it apart as a string value.
Last bit, I wanted a single CSV file for all my Exchange servers. There is no way I wanted to have 8 CSV files to sort through for all the mailbox information. Even more so, I didn't want to have to merge them all back together, this is a computer I am spending my life in front of.
Finally, I have to thank Microsoft for a great resource for converting my VBScript experience into Powershell. This site is an easy to understand reference for experienced VB scriptter who want to quickly learn PS.
Update (May 2008): In the BETA version of the Quest Active Roles Management shell includes a lastlogon field. This means you can quickly export the data without special formatting (like below).
For each account on your domain, this script returns.
Name: guest
LastLogonTimeStamp: May 1, 2008
LastLogon: May 7, 2008
AccountIsDisabled: False
AccountIsLocked: False
...
Re-route this to a CSV file, and you have something to share with the whole family!
Thanks Quest, Nice addition to this tool!
[end update]
Due to a DHCP failure, a client had to go through and set all their workstations to static IP addresses. This is approximately 75 workstations throughout their environment. This week, I am tasked with fixing their DHCP issues, and resetting all the workstations back to using DHCP.
This broad-stroke VBScript searches for all workstations in an environment, and queries their DHCP settings for all of them. By removing a single comment, the same script can be used to set all the same workstations to use DHCP (which can be dangerous).
It needs a little work troubleshooting. It gets settings for about 90% of the computers on the local domain, but some return nothing. It's pinging, so it must be on the network. Possibly the PC is using a non-standard NIC, that doesn't support WMI? Maybe a firewall is blocking the query? Maybe it has simply been too long and the computer has lost it's DHCP lease, and not gotten a new one (waiting for someone to use it)??
| Attachment | Size |
|---|---|
| DHCPUpdate.zip | 2.28 KB |
One of my current projects is helping with the removal of a legacy DNS server. I am reviewing Wireshark logs to determine which devices are statically set to utilize the old DNS servers. These devices range from servers and workstations to printers, digital senders and ILO servers. Each device should be logged into, and updated with the new DNS server IP address.
Here is my process:
Windows 2003 and XP IP addresses and created a new text file. Then I ran PSEXEC with my update script to touch each machine.
Hopefully these help you in your clean-up also!
| Attachment | Size |
|---|---|
| Scan Sniffer File.vbs.txt | 4.65 KB |
| dnsUpdate.vbs.txt | 4.52 KB |
| DNS_Cleanup.zip | 790 bytes |
I have been working on a number of projects lately where I need to touch most of the servers in our environment; be it changing DNS servers, or querying event logs, I needed a way to get every live server out there.
The attached script will query AD for all servers, then if pingable, it will attempt to gather more info via WMI. The final result is output to a CSV file in the C:\ root of the local computer.
On servers not running WMI, it will attempt to do a DOS Ping and then run NBTStat to gather the IP and MAC address.
| Attachment | Size |
|---|---|
| GetServerInfo_dyna.vbs_.txt | 7.38 KB |
We had a cluster issue with one of our Exchange 2007 CCR clusters. It didn't successfully failover when the virtual server quit responding. On this, we noticed that this server was still running Windows 2008 SP1.
This quick script exports all the windows versions and service packs for all current Exchange servers in your environment.
This project is to define the steps from inital site request description to final specification document for building a site.
This is inspired by the IBM Developer works series. While this will not be from an IA professional, this project will use some of the techniques to define a site design before it is built.
Background: My wife is a part time school teacher for a local middle school. She has been wanting to start a website for a number of years to improve the communications with her students and parents. Previous failed starts required a high level of sophistication and technical expertise, including experience coding HTML, or using FrontPage and FTP clients. By taking advantage of the Drupal engine for content management, my wife simply needs to enter her information and attach any handouts. I still get involved in some of the more complicated programming, but no longer need to create and edit content for her.
Also make sure to check out my completed document. I used the design of the website for a final paper in a class. The document is available here.
The Initial Description of the project was for an online website for a Middle School teacher. She intended the site to be used to provide a communications medium to parents, a "Homework Hotline". By providing parents with regular updates, the educator hopes that it will decrease the number of regular phone calls asking for homework updates. In addition, the site would provide sick and/or vacationing students a regular site to check for assignments.
The site must:
In addition, the site could:
Analysis
From the intial descriptions this seemed a posible job for page or book module and Event module. Upload, image and image_gallery modules as well.
When initial design of the site, I created a base site that I thought my client would like. Links to information, I thought she would use, created sample posts to populate the site and demonstrated the site to her. She hated it. Colors all wrong, layout didn't make sense and the website simply wouldn't work.
I started over with a different approach. I asked her to search for websites that contained content similar to what she wanted to post. Based on her results, we took each site she liked, and picked apart the different elements that she liked and what she did not like.
Based on her client base (parents and students in low-middle income households), I made a few suggestions.
Once we had the look and feel of the site closer to what the client expected, we could work on how she would use the site.
As part of my Master's program, I completed a detailed analysis of the site. This document includes design considerations for the site, customizations done to the site, and even basic build instructions. This should be helpful for an IT individual with experience installing Windows to build a similar site.
I am happy to say that I received an 'A' in the class and on this assignment!
| Attachment | Size |
|---|---|
| Eric Woodford TS5004 Final Paper.pdf | 461.92 KB |
While watching a rerun of NUMB3RS on TV, the mathmatician, Charlie, suggested to his dad that he should just right an algorithm to solve the Sudoku puzzles. Hmm, I could do that!
I started out writing a short vbscript that would attempt to solve the puzzle.
This could solve virtually all Easy and Moderate rated puzzles. When using attempting a Hard puzzle, it would fail when only squares with 2+ possible values remained.
Reading in a Sudoku puzzle book, they suggested a few additional methods and I added logic for these scenarios.
This allowed the script to solve several HARD puzzles that the previous script crashed on. Unfortunately, not all mulitple possible value scenarios have multiples.
Alright, now time to guess. To guess, the script does a few things.
If the first guess is wrong, it uses the post-guess values to revert the changes made. The script then attempts the second possible value in the guess. If this also fails, it reverts again, and finds another square.
During my practice runs, the script has completed 'Diabolical' level puzzles in a matter of seconds!! Solved scripts are saved to the root of C:\ in a CSV format.
| Attachment | Size |
|---|---|
| sudoku_8-4.zip | 6.83 KB |
Why not create a technical manual that these guys can relate to?
Introduction
You are the proud owner of OBGYN's latest model BABEE. This has been custom built using the latest genetic technology to compliment your very lifestyle. Please take a few moments and read through the entire manual before operating your BABEE. These delicate devices are extrememly sensitive to the environment and if not properly handled can cause you an enormous nightmare.
System Requirements
Out of the box, your BABEE unit has very basic requirements. Unfortunately they will likely not be tuned to your schedule for several weeks and we at OBGYN suggest that you take a few weeks off from your work schedule to accomodate your BABEE unit.
I/O
Inputs: Your new BABEE has sensitive audio/visual input sensors. Using NAI (non-artificial intelligence), it will soon learn to recognize you by sight and sound. This process typically takes 1-3 months. Until then, anyone who approaches your BABEE unit will be greeted similarly.
As mentioned above, you should quickly locate the power recharging input. The easiest method of recharging your unit is direct application of BABEE Low Gas Formula Fuel (BLGFF) to the input near the visual inputs. Upon delivery of the unit, until it can self-sustain, you or another engineer will need to recharge your BABEE unit. BLGFF can be located in several local retailers.
Outputs: Your BABEE unit has 2 basic outputs. Both of these outputs should be located immediately.
Alerts
Watch out! Your BABEE has very sophisticated alert system. It will notify you of every possible type problem. Unfortunately the alerting early off is rather confusing, sorry. (Click here to purchase a supplementary manual.) This was to make your unit versatile for international sales. Don't worry, as the unit localizes, it will soon learn to mimic your vocalizations and respond. Customers have reported positive results around 1 year of training. Use of manual communication has shown positive results also.
Beyond the audible alerts, also watch for leaking by the visual inputs, swinging of the appendages, and irritable spouses. These alternate alerts can often provide additional insight.
Training
To increase the functionality of your BABEE unit, it is never too late to start a rudimentary training regiment. After a few months, you should find that repetitive exposure to various inputs will help set in a routine. By maintaining a regular schedule of events, your young BABEE unit will start to respond accordingly. At first your focus should be to keep a regular schedule for feedings, morning and night time routines, and extra-curricular activities (like gym, walks, etc.).
For example:
After successful training, you will quickly find that your unit will start alerting you when a scheduled event is about to happen.
NOTE: Disregard all (except from a trained support professional) suggestions that your BABEE unit should be woken on regular intervals. This only trains your BABEE to wake on regular intervals, even after you have quit.
Congratulations, you have now completed one full year with your BABEE unit. During the last few months, you should have noticed some drastic changes. This chapter is to cover some of the additional challenges that come with your growing BABEE.
Mobility Starting at about 9 months, your BABEE unit probably started quad appendage mobility. As your BABEE strengthens, this will convert to two legged, then full speed running. Traction control is recommended to keep up with your BABEE unit, especially in crowded areas.
Safety Along with the increased mobility, comes the increased need for unit safety. Your BABEE unit has been programmed with innate curiosity. This is to help the unit learn faster, unfortunately, it also has no limits. You may find that your BABEE is attempting to climb up on your furniture, check the contents of the silverware drawer, and taste the cleaning fluid under your sinks. It is in your best interest to protect your unit. Here are a few useful tricks:
Interaction
With increased mobility, and if you have been working on the manual interaction method, your patience should be paying off. Somewhere around the 1 year mark, your unit should start showing signs of mimicking your language and vocal tonality.
This is a work in progress (I have a different story running through my head and can't seem to focus on this one.) ... check back for the entire document. Make sure to check out Chapter 1 of this book.
Working on servers, you inveriably need to reboot them. One of the primary tools I use to determine if a server has shut down is to PING the server.
This will PING the server repeatedly until I quit it. When the server goes down, it will return "Request Timed Out" instead of a valid PING response. Here is what it would look like when the server shuts down, then comes back up again.
Unfortunately, if you happen to miss the downtime (change screens, leave your desk, etc.) you'll never know what happened. Did the server reboot or has Windows crashed while trying to go down???
That's why I developed this little batch script. It utilizes the DOS PING command to monitor the status change. When the server successfully shuts down, it changes the display and waits for the server to come back up.
Highlight and copy the following code to your buffer (CTRL+C). Open notepad, and paste it into a new text file. Save that text file as PingAlive.bat. Copy this file into your system path (like C:\Windows\System32).
Now I can use my server reboots as coffee breaks and not worry about missing anything!
| Attachment | Size |
|---|---|
| PingAlive.zip | 564 bytes |
Tired of searching through racks and racks of servers to not find what your looking for?
Tired of having to run back to your desk to remote into that server to insert a CD?
Utilizing the power of PSExec, you can eject the CD drive remotely without having to leave your comfy desk.
| Attachment | Size |
|---|---|
| Eject Remote CD.zip | 21.21 KB |
When you are looking for something, like a piece of hardware, and you don't know where to start looking, it is always useful to have a good set of tools.
For example, I wanted to find what IP address that a new UPS device was using. I could not locate it in the DHCP tables and figured it must have a static IP address. The administration tools could not access it via the USB cable, so I needed to brute force search for the IP address. What I would do for an IP scanner right then? Code one!
The script below is a command-line script that uses WMI to check the pingstatus of the system at each IP address. I grabbed parts from Windows IT Pro. So far, it will only increment the last octet of the IP address. Maybe if the need arises, I will modify the code to take a start and end range.
Update:
After reviewing Scott's enormous list of his favorite tools, I found this one which appears to have a great GUI.
| Attachment | Size |
|---|---|
| PingIP.zip | 1.21 KB |
For quite some time, I have wanted to develop a batch script that I could use to automate the process of backing up my documents then email them to myself. Using my GMail account's enormous capacity, I can keep several copies of my documents accessible online without having to worry about drive space.
My requirements:
Here is the code that I came up with. I make use of DOS pipes in order to get my data.
When that is complete, I run the DOS Attrib command to turn off the attribute bit on all the files I compressed. Then I email myself the file using BLAT. Note, that I have set it to span the email into multiple 10mb attachments. You'll need to adjust this to match your outgoing SMTP server, and use an email program that can handle multipart UUEncoded attachments.
You'll need:
The full script is below.
Now that Daylight Saving Time has begun, I am constantly getting requests for help on why the calendar info is wrong. I suggest that maybe they need to install the Microsoft patch (931836). Unfortunately it is not easy to scan a computer to find a single patch. Since Service Pack 2, there has been at least 150 patches for various issues, updates, and such.
To make things easier, I found that the PSInfo will return all the patches for a specific computer. This will return all the patches on the local computer. Unfortunately, it does not appear that you can filter on a specific patch using the embedded 'filter' command of PSInfo (like you can for other components that it will return).
Great! Now I can have my Dad wade through 3 pages of hotfixes, looking for a specific number in the list. Of course, I can have him pipe it to a text file, then simply search the file in Notepad or such. Why? DOS has a great command called "FIND". This command will search an input source and return matching contents. So I have them type in:
This returns one line when it finds the patch:
and no patch info when it is not installed.
To extend this, I have considered taking advantage of the wildcard functionality in PSInfo. You could type "\\*" after the PSINFO statement and it would search all computers on the local network! Unfortunately, I've been told that this returns the number of computers with a give patch, not which ones. I'd suggest a BATCH FOR ... loop..
Thanks Mark, I love PSTools!
Working on network workstations, I found I needed a method to tell when they came online. I wanted a script to email me so I could receive it on my PDA when the connection worked. This way I could be working in the wiring cabinet and hear it successfully connect.
The following script can easily be modified to notify when a server is up or down. I've also added an option to loop the script continuously until specific triggers are met. These triggers can be set at the command line, or hard set into the code for quick deployment. You'll just need to put your email address into the script before you run it.
Requirements: Latest version of BLAT (note the path in line 75).
| Attachment | Size |
|---|---|
| Notify.zip | 906 bytes |
A new HR system is going to generate e-mails to every employee in the company. To accomplish this, about 200 people needed to have accounts created for them. To make administration easier, all 200 new accounts were added to a single AD Group, "Limited Use Employees".
Using Active Directory for Users and Computers (ADUC), you can query for individual names, groups, and even resources on the network, like computers, printers, etc.. If you have 200 people you are attempting modify, you can modify each one individually (ouch!!), you can modify the container they reside on (not bad, especially if you use a GPO), or you can a mass modify solution, like scripting or LDIFDE. LDIFDE work best if you have some field that ties them all together (same department, same company field, etc), but not so well if you don't. Scripting works great, but does require a bit of coding experience. Read file, find account, modify value, save user, repeat.
We wanted something simpler. ADUC has a built-in query function to allow you to build 'Saved Queries'. This option has a number of basic wizards that allow you to build various queries to search your AD environment. For example, finding all mail-enabled groups that don't have managers.
As I stated, we added all 200 employees to the same distribution list. This means if we could create a query to return all the members of a specific distribution group. I found only one way to get this query to work. You need to create the query so it points directly to the distinguishedname(DN) of your group. The DN can be found by searching ADSI Edit or you can build it by hand.
To build the DN by hand you need the value that's in the Canonical Name of Object field. This can be found on the Object tab in ADUC. It should look something like:
(where ... equals any number of sub-OU containers.)
The DistinguishedName simply reverses the information and describes each portion. So for my example, the distinguished name would be (NOTE: The '\' before the group name is required):
So, for the Advanced Filter, I put:
Member Of is (exactly) cn=\Limited Use,ou=Groups,dc=corp,dc=ent
Unfortunately after all this, I found out that you cannot modify Exchange Mailbox properties, like Delivery Restrictions, using this method. So I guess, we are back to the other options, individually (probably safer) or using a script.