Quantcast
Channel: Hey, Scripting Guy! Blog
Viewing all 3333 articles
Browse latest View live

BATCHman Faces the Distractful Poker and Recovers Deleted Active Directory Items

0
0

Summary: In today’s gripping episode, BATCHman squares off with the Distractful Poker and recovers items deleted from Active Directory Domain Services using Windows PowerShell.

 

Microsoft Scripting Guy Ed Wilson here. Windows PowerShell MVP Sean Kearney is with us again today with part 3 of the BATCHman series.

BATCHman and Cmdlet graphic

Whenever trouble happens in systems and people will call,
And darkness rolls out causing your fall,
Creatures of bits roam in the night,
Shine to the sky, the bright bluish light,

and call to…BATCHMAN!

…and, oh yes, his sidekick Cmdlet too.

 

In Today’s Episode: BATCHman encounters the Distractful Poker

A travesty has hit Redmond City! The mayor and his staff are unable to log in to Active Directory Domain Services!

“Quick! Get the chief to fire up the BATCHSignal and call BATCHman! We need his help now!”

Shining up to the sky, a gleaming Windows PowerShell signal cutting through the sky and the flight patterns of a few seagulls—the BATCHSignal! Within moments the WinMobile pulls up precariously holding up BATCHman and Cmdlet. The Mayor looks over. “Just how do the pair of you fit on that?” “Very carefully,” quips BATCHman. “So what has happened here today?”

“Oh BATCHman!” the mayor sobbed. “It was the Poker! He came behind the systems administrator, poked him in the side, distracted him, and deleted our user accounts! We can’t get into the system to issue paychecks to any of our staff! If we don’t solve this soon, we’ll have a major disaster on our hands!”

“Holy irritants, BATCHman! Not the Poker! Why the last time he was around…”

“Yes, Cmdlet, I know the story. Clippy was born. The Poker is truly a cruel one. But never mind that. Mayor! Quick take make to your datacenter! We don’t have one second to spare.”

In moments, BATCHman and Cmdlet stood before a console. BATCHman thought, “I could go dig up tapes and do an authoritative restore, but time is of the essence.” Quickly, he spun on his feet.

“Mayor, did you upgrade to Windows Server 2008 R2 as we suggested last time I chatted with you?”

“Why, yes. Yes, I think we did, BATCHman, but why do you ask?”

BATCHman smiled. “if we’re lucky, your administrator enabled the Active Directory Recycle Bin. I can check in moments.” On one of the Windows Server 2000 R2 domain controllers, BATCHman typed:

GET-ADOPTIONALFEATURE ‘Recycle Bin Feature’

“The results of this on the screen, Cmdlet, not only tell us about the feature, but also about what scope it applies to. By default, in a system where it’s not enabled, the EnabledScopes property will have no value.”

Image of EnabledScopes property

“As we can see, it has been enabled here. So now, what we need to do is determine just how much damage has been done by this evil villain. With the ActiveDirectory module, we can key this in to show all objects in Active Directory, including anything that is in the Active Directory Recycle Bin.”

Get-ADObject -filter * –IncludeDeletedObjects

“But BATCHman!” Cmdlet spoke up. “Wouldn’t that be too much? What if we’re dealing with 50,000 objects? There must be a way to only show what was deleted!”

BATCHman nodded. “Correct. So now if we run the GET-MEMBER cmdlet against the output like this…”

Get-ADObject -filter * –IncludeDeletedObjects | GET-MEMBER

“…we’ll see there is a property called DELETED which contains a Boolean TRUE if that value is deleted. For this, we will add a filter to the statement.”

Get-ADObject –filter ‘Deleted –eq $TRUE’ –IncludeDeletedObjects

“Now we can see only deleted items in Active Directory so…”

“Holy undo, BATCHman! Is there a restore we can just pipe the output to?”

BATCHman nodded. “Yes. But what we need to do is restore the tree first. At this point, let’s pipe the output into the Out-GridView cmdlet to have an easier way of viewing the data.”

Get-ADObject –filter ‘Deleted –eq $TRUE’ –IncludeDeletedObjects | OUT-GRIDVIEW

BATCHman cautiously examined the list. “It appears we should be able to pull out all members of the tree by filtering on ObjectClass and pulling down those with the property OrganizationalUnit. So we just need to add an extra filter to our statement.”

Get-ADObject –filter ‘Deleted –eq $TRUE –and Objectclass –eq “OrganizationalUnit”’ –IncludeDeletedObjects | OUT-GRIDVIEW

“Now all we need to do is pipe this output into the Restore ADObject to get the tree back.”

Get-ADObject –filter ‘Deleted –eq $TRUE –and Objectclass –eq “OrganizationalUnit”’ –IncludeDeletedObjects | RESTORE-ADOBJECT

“Now with the tree restored, we can just restore the rest of the objects remaining using a simpler statement because we’ve already restored the tree. The rest of the objects we have are probably users, so we can drop the second filter and just restore.

Get-ADObject –filter ‘Deleted –eq $TRUE –and Objectclass’ –IncludeDeletedObjects | RESTORE-ADOBJECT

In moments, the task was complete. “Cmdlet, have somebody try to log in to the system!” The mayor quickly logged in to verify all worked well. Quickly he called up the accounting department to let them know they could log in to the systems. Paychecks would be out today!

“BATCHman! How can we ever thank you?”

“Just keep doing things the way you are with Windows PowerShell: it was the true superhero today!”

 

Thank you, Sean, for today’s spell-binding article. Sean will be back next weekend with the concluding episodes of BATCHman. Same BATCHtime, same BATCHchannel.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

 

 


Use Active Directory Cmdlets with PowerShell to Find Users

0
0

Summary: Learn about the Microsoft Active Directory Windows PowerShell cmdlets, and use them to find active and disabled users.

 

Hey, Scripting Guy! QuestionHey, Scripting Guy! I am wondering what the best way is to use Windows PowerShell to work with Active Directory. I have seen all different methods talked about on the Internet, and many of them require downloading and installing third-party software. Can you possibly discuss how to work with Active Directory and Windows PowerShell, and maybe even discuss the pros and the cons of each approach? It would help us at work as we try to set our strategic direction.

—TU

 

Hey, Scripting Guy! AnswerHello TU,

Microsoft Scripting Guy Ed Wilson here. This week, the Scripting Wife and I are lying around on the beach in Kauai. Kauai, Hawaii, is a wonderful island that is like a garden paradise, with cobalt blue water that is so clear you can often see the ocean bottom while standing on the deck of a boat. Here is a picture of a turtle I took on my last dive trip to the island.

Photo Ed took of a sea turtle in Kauai, Hawaii

My first choice for working with Active Directory from within Windows PowrShell, is to use the Active Directory cmdlets that are supplied with Windows Server 2008 R2. There are actually a couple of ways to use these cmdlets. One way is to install the Remote Server Admin Tools (RSAT) for Windows Server 2008 R2 onto your Windows 7 computer. A link to these tools is on the Script Center Downloads page. There is a package for each version of Windows 7 (x86 and x64), as well as a build that is service-pack specific. Unfortunately, the installation cannot run from a server share, so the package must be copied locally. After it is copied, the installation proceeds without interruption. But that does not give you access to the actual tools; it simply places the files on your computer.

The first thing to do:

  1. Click the Start button, and then, on the Start menu, click Control Panel.
  2. Click Programs and Features and then click Turn Windows Features on or off.  
  3. Click Windows Features to see if the RSAT tools are installed on the computer.

As shown in the following figure, on a default installation of Windows 7, the RSAT tools are not installed.

Image showing RSAT not installed

When I attempt to install the RSAT tools, I am prompted for administrative credentials, as shown in the following figure. A normal, non-elevated user cannot install the tool set.

Image of prompt for administrative credentials

I provide credentials. Everything should be groovy. Wait, not yet. I am now prompted to install update KB958830. What in the world is that? Well, it is the technical name for RSAT. Click Yes, accept the license agreement, and there will be no more prompts.

Image of prompt to install RSAT

After the tools are installed, follow steps 1–3 above, find the Remote Server Administration Tools section, and choose the tools you want to make available. Unfortunately, this requires quite a bit of clicking because there is no way (that I know of) to click once and make all the tools available. The one tool you definitely do not want to inadvertently miss is under AD DS and AD LDS tools – Active Directory Module for Windows PowerShell. This critical check box is shown in the following figure.

Image of critical check box you must select

After the RSAT tools have been installed and configured, the next step is to import the activedirectory module. To do this, use the Import-Module cmdlet, as shown here:

Import-Module activedirectory

On my system, at times this command generates this warning message: “WARNING: Error initializing default drive: 'Unable to find a default server with Active Directory Web Services running.'”

The warning is generated because I have several domain controllers, and not all of them have the Active Directory Management Gateway Service installed. Depending on which domain controller authenticated my workstation, the warning appears. The solution is to install the Active Directory Management Gateway Service on all of the non-Windows Server 2008 R2 domain controllers. The other solution is to ignore the warning and specify the server parameter each time when using one of the cmdlets (but that will mean the PSDrive will be unavailable).

More than six years ago, a different Microsoft Scripting Guy wrote an article called How Can I Get a List of All the Disabled User Account Accounts in Active Directory? it was an immediate classic that continues to generate discussion even today. The VBScript to retrieve disabled user accounts is cryptic at best and downright confusing at worst. It is not horribly long, as far as VBScripts go; it checks in at 16 lines of code. It also uses COM-based ADO, which as far as VBScripters go is part and parcel of the game. No, it is not the VBScript or the ADO that is confusing; it is the UserAccountControl bitmask attributes that are the game changer.

Luckily, for those of us who are using Windows PowerShell and the Microsoft Active Directory cmdlets, it takes a single line of code to retrieve the disabled users in the domain. The command is shown here (keep in mind that before running this command, I had imported the activedirectory module into the current Windows PowerShell host):

Get-ADUser -Filter 'enabled -eq $false' -Server dc3

Not only is the command a single line of code, but also it is a single line of readable code. I really do not need to explain the command at all because the code is clearly understandable. I get users from Active Directory, and I use a filter that looks for the enabled property set to false. I also specify that I want to query a server named dc3 (the name of one of the domain controllers on my network). The command and the associated output are shown in the following figure.

Image of command and associated output

If I want to work with a specific user, I can use the identity parameter. The identity parameter accepts several things: DistinguishedName, SID, GUID, and SamAccountName. Probably, the easiest one to use is the SamAccountName. This command and associated output are shown here.

PS C:\Users\ed.IAMMRED>    Get-ADUser -Server dc3 -Identity teresa

 

DistinguishedName : CN=Teresa Wilson,OU=Charlotte,DC=iammred,DC=net

Enabled           : True

GivenName         : Teresa

Name              : Teresa Wilson

ObjectClass       : user

ObjectGUID        : 75f12010-b952-4d16-9b22-3ada7d26eed8

SamAccountName    : Teresa

SID               : S-1-5-21-1457956834-3844189528-3541350385-1104

Surname           : Wilson

UserPrincipalName : Teresa@iammred.net

 

To use the DistinguishedName value for the identity parameter, I need to supply it inside a pair of single or double quotation marks. This command and associated output are shown here.

PS C:\Users\ed.IAMMRED>    Get-ADUser -Server dc3 -Identity 'CN=Teresa Wilson,OU=Charlotte,DC=iammred,DC=net'

 

DistinguishedName : CN=Teresa Wilson,OU=Charlotte,DC=iammred,DC=net

Enabled           : True

GivenName         : Teresa

Name              : Teresa Wilson

ObjectClass       : user

ObjectGUID        : 75f12010-b952-4d16-9b22-3ada7d26eed8

SamAccountName    : Teresa

SID               : S-1-5-21-1457956834-3844189528-3541350385-1104

Surname           : Wilson

UserPrincipalName : Teresa@iammred.net

 

It is not necessary to use quotation marks when using the SID for the value of the identity parameter. This command and associated output are shown here.

PS C:\Users\ed.IAMMRED>    Get-ADUser -Server dc3 -Identity S-1-5-21-1457956834-3844189528-3541350385-1104

  

DistinguishedName : CN=Teresa Wilson,OU=Charlotte,DC=iammred,DC=net

Enabled           : True

GivenName         : Teresa

Name              : Teresa Wilson

ObjectClass       : user

ObjectGUID        : 75f12010-b952-4d16-9b22-3ada7d26eed8

SamAccountName    : Teresa

SID               : S-1-5-21-1457956834-3844189528-3541350385-1104

Surname           : Wilson

UserPrincipalName : Teresa@iammred.net

 

Once again, I can also use the ObjectGUID for the identity parameter value. It does not require quotation marks either. This command and associated output are shown here.

PS C:\Users\ed.IAMMRED>    Get-ADUser -Server dc3 -Identity 75f12010-b952-4d16-9b22-3ada7d26eed8

 

DistinguishedName : CN=Teresa Wilson,OU=Charlotte,DC=iammred,DC=net

Enabled           : True

GivenName         : Teresa

Name              : Teresa Wilson

ObjectClass       : user

ObjectGUID        : 75f12010-b952-4d16-9b22-3ada7d26eed8

SamAccountName    : Teresa

SID               : S-1-5-21-1457956834-3844189528-3541350385-1104

Surname           : Wilson

UserPrincipalName : Teresa@iammred.net

 

TU, that is all there is to using Windows PowerShell with Active Directory. Active Directory Week will continue tomorrow.

 

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

 

 

Install Active Directory Management Service for Easy PowerShell Access

0
0

Summary: In this step-by-step blog post, the Microsoft Scripting Guy covers installing the Active Directory Management Service for Windows PowerShell access to Active Directory Domain Services.

 

Hey, Scripting Guy! QuestionHey, Scripting Guy! I read with interest your blog post yesterday about using the Microsoft Windows PowerShell cmdlets to work with users in Active Directory. The problem is that I have a Windows 2008 domain controller, so the cmdlets do not appear to work for me. Is there something I can do to allow access to the Windows PowerShell cmdlets for Active Directory?

—IH

 

Hey, Scripting Guy! AnswerHello IH,

Microsoft Scripting Guy Ed Wilson here. The week in Kauai, Hawaii, is shaping up to be a nice one. The Scripting Wife and I have enjoyed traveling the island. It is actually our fourth trip to the island, and one of our favorite spots for mellowing out and relaxing. I took the following photo from a dive boat on our last trip to the island.

Photo of Kauai, Hawaii, taken by Ed

The first thing to do is to check the level of the .NET Framework that is installed on the domain controller to be updated. It must be running .NET Framework 3.5 with Service Pack 1. One easy way to check for the .NET Framework version is via Control Panel/Programs and Features. If .NET Framework 3.5 SP1 is installed, it appears as shown in the following figure.

Image showing .NET Framework 3.5 SP1 is installed

I download the Windows6.0-KB968934-x86.msu file from the Microsoft Download Center, as shown in the following figure.

Image of Microsoft Download Center page

After the file is downloaded, I run the program. The Windows Update standalone installer starts, and it searches for updated files. After about a minute or so, an error message appears. The message is the one shown in the following figure.

Image of error showing update does not apply to system

There are two hotfixes that are required (and there are three options available—a .NET Framework update and an operating system–specific update), but because I am running Windows Server 2008 with Service Pack 2 on my domain controller, the KB967574 hotfix is already installed, so I do not need to install that particular update.

The system requirements section is difficult to read (I have seen several forum postings attesting to this fact). The first hotfix applies to both Windows Server 2008 and Windows Server 2003. It is a hotfix that is described in KB article 969166, This is a .NET Framework 3.5 SP1 hotfix rollup. According to the KB article, the hotfix rollup is included in the .NET Framework 4.0. However, I have the .NET Framework 4 Client Profile and the .NET Framework 4 Extended updates, as well as all .NET 4 Framework updates, and the hotfix rollup from KB 969166 is not included in any of those packages. The good thing is that after installing the 969166 update, a reboot is not required and the installation will proceed with the dialog that appears here (assuming you have the other updates).

Image of dialogue box prompting installation of KB968934

For Windows Server 2003 and Windows Server 2003 R2, there is a specific hotfix that is described in KB 969429 to help Windows 7 clients to be able to find the management gateway. The third hotfix that is listed applies to Windows Server 2008. This hotfix, KB 967574, applies if you have not installed Service Pack 2 on the system.

After the two updates are applied to the system and the Active Directory Management Gateway Service is installed, a reboot of the server is required. After the Windows 2008 domain controller completes the reboot and the Active Directory Management Gateway Service is running, I can connect to it with Windows PowerShell from my Windows 7 desktop. Before attempting this, I open the services.msc utility and verify that Active Directory Web Services service is created and running. This service is shown in the following figure.

Image showing Active Directory Web Services is running

One thing that does not happen is there is no ActiveDirectory module available on the Windows Server 2008 Domain Controller, or Windows Server 2003 Domain Controller. Therefore, even though the management gateway is created, it does not provide any of the Active Directory cmdlets. This normally is not a problem, because of the availability of the RSAT tools for Windows 7.

On my Windows 7 desktop, I use the following command to import the Active Directory module:

Import-module ActiveDirectory

When I press Enter, I get a progress dialog displayed in the Windows PowerShell console. This progress bar is shown in the following figure.

Image of progress bar

In yesterday’s Hey Scripting Guy blog article, I talked about an error that I sometimes receive when the ActiveDirectory module is unable to talk to the specific domain controller that authenticated my logon. With the installation of the Active Directory Management Gateway Service on my DC1 server, I no longer receive that error.

I decide to do a quick test to ensure that everything is working. First, I do a query for a user named ed, but I do not specify the server. The command and results are shown here:

PS C:\Users\ed.IAMMRED> Get-ADUser ed 

 

DistinguishedName :       CN=ed wilson,OU=Charlotte,DC=iammred,DC=net

Enabled           :             True

GivenName         :          ed

Name              :             ed wilson

ObjectClass       :                        user

ObjectGUID        :          bb10b5a2-58d7-4f8a-ab10-2ee84fc7cb58

SamAccountName    :     ed

SID               :                S-1-5-21-1457956834-3844189528-3541350385-1103

Surname           :                        wilson

UserPrincipalName :       ed@iammred.net

 

Now I want to test a couple of my domain controllers to ensure they answer. I type two of the server names, pipe them to the ForEach-Object cmdlet (% is an alias), and inside the script block, I use the Get-ADUser command. I then select only the name attribute. The command and associated output are shown here:

PS C:\Users\ed.IAMMRED> "dc1","dc3" | % {get-aduser ed -server $_} | select name

 

name

ed wilson

ed wilson 

Sweet! I looks like everything installed properly. Speaking of sweet, I think the Scripting Wife and I will head out and try to find a locally grown pineapple freshly gleaned from the ground. Sounds like super fun to me. Aloha.

IH, that is all there is to installing the Active Directory Management Gateway Service. Active Directory Week will continue tomorrow.

 

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

 

 

Use PowerShell to Find Locked-Out User Accounts

0
0

Summary: Use a one-line Windows PowerShell command to find and unlock user accounts.

 

Hey, Scripting Guy! QuestionHey, Scripting Guy! I am trying to find users who are locked out. For example, I have a number of users who log on only occasionally. They constantly lock themselves out. I have seen some VBScripts to search for locked out user accounts, and even a Windows PowerShell script to accomplish the same thing, but I am wondering if there is an easier way to accomplish this task. Help, please!

—CJ

 

Hey, Scripting Guy! AnswerHello CJ,

Microsoft Scripting Guy Ed Wilson here. One problem with going on vacation is that the vacation eventually ends. I keep thinking that if we could sell our house in Charlotte, North Carolina, I might like to move to Hawaii to live. Right now, though, very few houses are actually selling in Charlotte, so there is little hope of making that move. One cool thing about living in Hawaii is that it is a couple of hours later than Redmond, Washington (Redmond is -8 GMT and Hawaii is -10 GMT). (This means that the next time someone schedules a meeting for 4:00 P.M. on a Friday, it would be 2:00 P.M. for me instead of the normal 7:00 P.M. meetings I get these days.)

CJ, I know exactly your predicament. You have users hiding in Active Directory Domain Services (AD DS) who are only occasional users. AD DS is essentially a database, and the old adage certainly applies: garbage in, garbage out. If a user cannot remember their password, the usefulness of network security diminishes rapidly. In addition, with the integration of directory services with messaging platforms, forgotten passwords can cause problems. However, when one has hundreds or thousands—or even hundreds of thousands of users—in Active Directory, finding a locked-out user can be as big of a challenge as finding the frogfish in the picture I took during my last scuba diving trip to Kauai.

Photo Ed took of a frogfish

Note   This is the third in a series of three posts about working with the ActiveDirectory module. In the first post, I discussed the RSAT tools and the Get-ADUser cmdlet. In the second post, I talked about installing the Active Directory management web service. For additional Active Directory and Windows PowerShell posts, refer to this collection on the Hey, Scripting Guy! Blog.

When using the Microsoft Active Directory cmdlets, locating locked-out users is a snap. In fact, the Search-ADAccount cmdlet even has a lockedout switch.

The first thing to do is to import the ActiveDirectory module by using the Import-Module cmdlet. This command is shown here:

Import-Module activedirectory

Once the module is imported, use the Search-ADAccount cmdlet with the lockedout parameter. This command is shown here:

Search-ADAccount –LockedOut

Note   Many network administrators who spend the majority of their time working with AD DS import the ActiveDirectory module via their Windows PowerShell profile. In this way, they never need to worry about first importing the module. I have an entire series of posts about working with profiles that discusses how to create a profile, and what sort of things to add to it.

The Search-ADAccount command and the associated output are shown in the following figure.

Image of Search-ADAccount and associated output

I can unlock the locked-out user account as well, assuming I have permission. In the following figure, I attempt to unlock the user account with an account that is a normal user. And an error arises.

Note   People are often worried about Windows PowerShell from a security perspective. Windows PowerShell is only an application, and a user is not able to do anything that they do not have rights or permission to accomplish. This is a case in point.

Image of error

Because the myuser account does not have administrator rights, I need to start Windows PowerShell with an account that has the ability to unlock a user account. To do this, I right-click the Windows PowerShell icon while pressing Shift. This allows me to click Run as different user in the shortcut menu. This produces the dialog box shown in the following figure.

Image of Run as different user dialog box

After I start Windows PowerShell again with an account that has rights to unlock users, I need to import the ActiveDirectory module once again. I then check to ensure that I can still locate the locked-out user accounts. After I have proven to myself I can do that, I pipe the results of the Search-ADAccount cmdlet to Unlock-ADAccount. A quick check ensures I have unlocked all the locked-out accounts. The series of commands is shown here:

import-module ActiveDirectory

Search-ADAccount –LockedOut

Search-ADAccount -LockedOut | Unlock-ADAccount

Search-ADAccount –LockedOut

 

The commands and associated output are shown in the following figure.

Image of commands and associated output

Note   Keep in mind that the command Search-ADAccount -LockedOut | Unlock-ADAccount will unlock every account that you have permission to unlock. In most cases, you will want to investigate before unlocking all locked-out accounts. If you do not want to unlock all locked-out accounts, use the confirm switch to be prompted before unlocking an account.

If I do not want to unlock all users, I user the confirm parameter from the Unlock-ADAccount cmdlet. As an example, I first check to see which users are locked out by using the Search-ADAccount cmdlet, but I do not want to see everything, only their names. Next, I pipe the locked-out users to the Unlock-ADAccount cmdlet with the confirm parameter. I am then prompted for each of the three locked-out users. I choose to unlock the first and third users, but not the second user. I then use the Search-ADAccount cmdlet one last time to ensure that the second user is still locked out. The following figure illustrates this technique.

Image of technique illustrated

CJ, that is all there is to finding and unlocking users in Active Directory by using the Microsoft ActiveDirectory module. I invite you back tomorrow when I will make a historic announcement. It is good, so check back. You will be glad you did.

 

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

 

 

Honorary Scripting Guys Announced

0
0

Summary: Microsoft Scripting Guy Ed Wilson announces the first ever Honorary Scripting Guys. 

Honorary Scripting Guy image 

Microsoft Scripting Guy Ed Wilson here. Today I have an exciting announcement! Drum roll please: dadadadadadada…CLING! Yes, for the first time ever, we now have official Honorary Scripting Guys! Yes, that’s right. What does it take to become an official Honorary Scripting Guy? It takes an extreme commitment to the scripting community, a remarkable dedication helping to spread the good word about Windows PowerShell, and a relentless pursuit of excellence in producing exceptional content. The first five Honorary Scripting Guys are (in no particular order):

  • Sean Kearney
  • James Brundage
  • Don Jones
  • Tome Tanasovski
  • Trevor Sullivan

Let me tell you a little bit about each of these scripting stalwarts. We will begin at the top of the list, and work our way down. Or to put it another way, we will begin with Sean and conclude with Trevor.

 

Sean Kearney

Sean Kearney is our most prolific guest blogger. Check out his guest blog posts.

Photo of the inimitable Sean Kearney

Sean Kearney is an infrastructure support analyst and Microsoft MVP in Windows PowerShell. He is absolutely passionate about automation technologies, especially Windows PowerShell. If you say, “PowerShell,” he may just break into song. Sean considers himself “just a tech at heart,” but he often can be found dabbling with most Microsoft technologies. We have been advised that any rumors about him ever singing for the Microsoft JobsBlog are completely unfounded. Complete rubbish. Let’s just keep it between us, okay?

Sean's contact information:
Twitter: EnergizedTech
Blog: Energized About Technology
Website: PowerShell: Releasing the Power of Shell to You

 

James Brundage

James Brundage has contributed several guest blog posts.

James is the founder of Start-Automating, a company dedicated to saving people time and money by helping them automate. Start-Automating offers Windows PowerShell training and custom Windows PowerShell and .NET Framework development. James formerly worked on the Windows PowerShell team at Microsoft. You can follow James on Twitter (@jamesbru) or on the Start-Automating company blog.

 

Don Jones

Don Jones is our next Honorary Scripting Guy. Check out his guest blog posts.

Photo of Don Jones

Don is a Windows PowerShell MVP Award recipient, and he is one of the world’s most well-known Windows PowerShell authorities. He blogs about Windows PowerShell, writes about Windows PowerShell, and offers private on-site Windows PowerShell classes. He recently released a book for Windows PowerShell beginners, helping them Learn Windows PowerShell in a Month of Lunches.

 

Tome Tanasovski

Photo of Tome Tanasovski 

We continue this list of most excellent guest bloggers and Honorary Scripting Guys with Tome Tanasovski. Read Tome’s guest blog posts.

Tome is a Windows engineer for a market-leading, global financial services firm in New York City. He is the host of the PowerShell Cmdlet of the Day Podcast, the founder and leader of the New York City PowerShell User Group, a cofounder of the NYC Techstravaganza, a blogger, a speaker, and a regular contributor to the Windows PowerShell forum. He is currently working on the Windows PowerShell 2.0 Bible, which is due out in 2011 from Wiley. Tome is also a recipient of the MVP Award for Windows PowerShell.

 

Trevor Sullivan

We round out this list of Honorary Scripting Guys with Trevor Sullivan. Read Trevor’s guest blog posts.

Photo of Trevor Sullivan

Trevor is a passionate, experienced, and Microsoft-certified IT pro with more than seven years in the industry. Although he is interested in nearly all Microsoft technologies, his primary specialties include:

  • Design, implementation, and troubleshooting of Microsoft System Center Configuration Manager 2007.
  • Automation using Windows PowerShell, Windows Management Instrumentation (WMI), Active Directory Services Interface (ADSI), and the Microsoft .NET Framework.

Trevor is a Microsoft-recognized Community Contributor (MCC) and is active in several online communities:

One of his major achievements is the development and public release of an open-source Windows PowerShell module called PowerEvents. During his personal time, he enjoys studying theology, spending time with his girlfriend, being outdoors, shooting photos, playing video games, testing software, and learning about all sorts of new things.

 

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

 

 

BATCHman Uses PowerShell to Thwart Dr. Regex and Save the Zoo

0
0

Summary: In this exciting episode, BATCHman uses Windows PowerShell and regular expressions to thwart the evil Dr. Regex and save the monkeys.

 

Microsoft Scripting Guy, Ed Wilson, is here. Sean Kearney is back with us for three more episodes of the thrilling BATCHman series. Today is Episode 4.

BATCHman and Cmdlet logo

Whenever trouble happens in systems and people will call,
and darkness rolls out causing your fall,
Creatures of bits roam in the night,
Shine to the sky, the bright bluish Light,

and call to…BATCHman !

…and, oh yes, his sidekick Boy Blunder Cmdlet, too.

 

In Today’s Episode, BATCHman Encounters Doctor Regex!

Cutting through the midnight blue sky, a beacon for justice, a light for freedom calls out!

“Holy shell, BATCHman! It’s the BATCHsignal! We have…”

“Ahem, Cmdlet, I would suggest you watch your language there. This is after all a ‘G’ rated blog post.”

“But but, I…I…ugh…yes, BATCHman,” he sullenly bowed in defeat. “Shall I fire up the WinMobile?”

“No, but you can start it,” snickered our hero. “To the WinMobile!”

Buckling under the weight of our heroes, the WinMobile moved off. “Thank goodness it’s made of Gorilla Glass,” muttered Cmdlet.

Meanwhile, somewhere else in the city of Redmond, evil has placed a call. The arch criminal simply known as the dreaded Dr. Regex has visited. Cursed after too many nights of writing parse queries, our arch villain only speaks in riddles of Regex. He has taken the team at the local Redmond Zoo by surprise. All the cages are being unlocked, potentially unleashing the vicious GUI eating SAPIEN monkeys! Our arch villain dances off on top of the cages laughing maniacally in an oddly cheeseburger colored jumpsuit with his big “!” symbol. “Muah ha haaaaa!”

The only passcode to the electronic Chubb lock system has been left somewhere in this cryptic riddle left on Notepad on the desktop of the main server:

Evil may Come And Evil May Go
The BATCHman Will Seek, be Fast Or Be Slow
But Soon On the Day The pass It Must Be
The word Should He Say, To Not Set Them Free
is The BATCHman Too Smart, Or Is He Not Bright?
under The Stars And Under the Light!
The key We Shall See, Unlocking This Clue
Will chain Them All Down, Or Let Them Run Through

Signed ^[Dr!Regex]^ 

Photo of the evil Dr. Regex

BATCHman and Cmdlet arrive on the scene, the sound of Monkeys about to tear scripts apart. Cmdlet stared at the riddle. “Holy twisted blisters, BATCHman! That must have worn out somebody’s fingers typing! What a bizarre rid…”

“….bizarre clue!” corrected BATCHman “Yes. Yes, indeed. What a strange person. There must be some type of pattern in this clue. Something usual to the naked human eye, something I can’t quite see, some…”

“BATCHman! It appears only certain words start with a lowercase letter!”

“Cmdlet! Excellent ! How did you spot it so quickly?”

“It’s written here in the plot, page 5, line 7…”

BATCHman looks down scratching his cowl. “Ah, so it is.”

“So we could just write down every word,” suggested Cmdlet.

“Pah! And waste a good chance to use Windows PowerShell? Never! This is a perfect opportunity to use regular expressions to find those matches! First, we need to identify the pattern. We need all words starting with a lowercase letter only. Within regular expressions, that would be a matter of specifying that the first letter is from a to z only like this.”

[a-z]

“And then we’ll need to specify it’s at the beginning of the word.”

\b[a-z]

“Then we’ll specify that the word must be at least two letters long if we find it, but can be as long as we want. This should trap our series of words.”

\b[a-z]{2,}

“With this in place, Cmdlet, we need to pipe the information from the text file into a Select-String statement like this.”

GET-CONTENT C:\EVILCLUE.TXT | SELECT-STRING ‘\b[a-z]{2,}’

Cmdlet sat there cross-legged watching the magic unfold. “But how do we tell it to look for more than one instance, BATCHman? How does it know it is lowercase?”

“Presently it doesn’t, but it will if we add more parameters to our Select-String. One is -allmatches in case there is more than one instance per line. The other is -casesensitive because Select-String by default just does a –match which doesn’t care about uppercase or lowercase.”

GET-CONTENT C:\EVILCLUE.TXT | SELECT-STRING ‘\b[a-z]{2,}’ –casesensitive –allmatches

Evil may Come And Evil May Go
The BATCHman Will Seek, be Fast Or Be Slow
But Soon On the Day The pass It Must Be
The word Should He Say, To Not Set Them Free
is The BATCHman Too Smart, Or Is He Not Bright?
under The Stars And Under the Light!
The key We Shall See, Unlocking This Clue
Will chain Them All Down, Or Let Them Run Through

Cmdlet looked and laughed. “Holy foot in mouth! The output is the same!”

The BATCHman smiled. “Not quite. If we run Get-Member against this output, you’ll see something different.”

GET-CONTENT C:\EVILCLUE.TXT | SELECT-STRING ‘\b[a-z]{2,}’ –casesensitive –allmatches | GET-MEMBER

“This, Cmdlet, is not just a string. We can see there are properties such as Matches. If we were to look at the properties of Matches, we mind find something interesting.”

GET-CONTENT C:\EVILCLUE.TXT | SELECT-STRING ‘\b[a-z]{2,}’ –casesensitive –allmatches | SELECT-OBJECT Matches

Image of matches

“Holy obvious! Do you mean…” looking to his left Cmdlet lifts the keychain to the old cages. A Big envelope with the words “^[Dr!Regex]^” is written on it. He bites it open and his mouth drops sullenly.

“What is it, Cmdlet?”

“Another clue. Awww, come on!!!” Cmdlet stomps about like a little child having a hissy fit showing the new clue to BATCHman.

Remove ME now and unlock the clue

‘meHeymeheymewemearemethemescriptmemonkeesmeandmepeoplemesaymewemearemescriptingmeawayme’

BATCHman looks. “I’m seeing an awful lot of ME in this particular line. I will bet we could just use a –replace on it!

“What’s that?”

Seating himself down in front of the Windows PowerShell console, he explains. “Replace is another part of regular expressions where we can replace one thing with another.”

‘meHeymeheymewemearemethemescriptmemonkeesmeandmepeoplemesaymewemearemescriptingmeawayme’ –replace ‘me’,’’

“That will replace every reference of me with nothing, which gives us this result.”

Heyheywearethescriptmonkeesandpeoplesaywearescriptingaway

“Cmdlet, please try this password on the Chubb security system. I’m sure you’ll find it works; just press the Lock All Cages button.”

Soon echoing through the Redmond Zoo, massive sounds of *KLANG* echo throughout with the odd *yelp* as the occasional finger gets pinched on closing doors.

With one loud *THUD*, Dr. Regex falls into bushes below. “Waaaaihihghghhgih!!”

The keeper of the Redmond Zoo looks up. “Oh, BATCHman! How can ever thank you?”

“Easy, good citizen. One, do not put your master security password under a set of keys to the Monkey House and…do you have something I could scrape my shoes on? I think I stepped on something near the cages.”

 

Thanks, Sean, for another exciting episode of BATCHman! Join us tomorrow for Episode 5.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

 

 

BATCHman Foils the Fowl Ping Win and Repairs the Registry

0
0

Summary: In this episode, superhero BATCHman foils the fowl villain Ping Win and repairs the registry.

 

Microsoft Scripting Guy Ed Wilson here. Today is Episode 5 of the BATCHman series by Sean Kearney.

Note   You can read all gripping, engaging, informative, and downright funny BATCHman episodes.

BATCHman and Cmdlet logo

Whenever trouble happens in systems and people will call,
and darkness rolls out causing your fall,
Creatures of bits roam in the night,
Shine to the sky, the bright bluish light,

and call to…BATCHman !

…and, oh yes, his sidekick Boy Blunder Cmdlet, too.

 

In Today’s Episode, BATCHman Encounters Ping Win

Flying through the night in the new BATCHcopter, BATCHman begins veering off course dramatically.

“Aiaighahighiahgihi!!! My eyes! Such BRIGHT BLUE LIGHT!”

“Holy bluebird of sharpness!” screams Cmdlet. “It’s the BATCHsignal!”

“Yes, Boy Blunder, trouble calls us.” BATCHman calls up the new crime fighting one-liner:

GET-TROUBLE | INVOKE-LAND –location $_.Source

In moments, they are at the scene, the trouble, the issue at hand. It appears that all the firewalls at the Redmond Community Center have been shut down somehow! Home pages have been set to “pingwinrulez.com”! All search queries have been routed to pingwinrulez.com. What dastardly villain would do such a thing?

“Holy earthworm, BATCHman! All of these computers accessed by kids! Surfing whatever they want unprotected! What villain, what creature of the night, who would do.…”

BATCHman taps Cmdlet on the shoulder and points to a rather obvious character off to his left.

Cmdlet looks. “Holy mackerel, BATCHman! It’s the Pin…”

“Ahh, Boy Blunder.” BATCHman taps the side of his nose shaking his head.

“Oh…er…uh…right…it’s…it’s…” Cmdlet stammers staring at the oddly dressed black-and-white flightless fowl-looking person.

The strange character sees the Static Duo. “Meh. Allow me to introduce myself. I am…,” he pauses dramatically before he rips open his jacket, “…PING WIN! Meh heh hehe!”

The words “PING WIN” flash in a mad pulsing fashion, surrounded in blinking lights from a large, very expensive-looking neon sign hanging over his shirt.

BATCHman pauses for a moment, looking. “Ah” is all he can say. He looks at Cmdlet. “Was this really necessary?”

Cmdlet nods. “The blog post went way under budget. We had to burn up some funds. Cool shirt, eh?”

Getting a hold of himself, BATCHman gets back into character. “So Ping Win, you’ve downed all the firewalls, eh? To what end? Why?”

“Antivirus Software! To rid themselves of this problem and all the annoying popups, it will advertise nothing but PingWin-Nev-R-Fayl Antivirus! I will become a trillionaire! Muah har herh hah!”

As Ping Win dances his previctory dance, he trips over one of fifty wires running the neon lights on his shirt and collapses, knocked senseless by his own silliness.

“I thought he’d never shut up!” muttered Cmdlet. “So BATCHman, how do we solve this?”

“How else? With a BATCH file and some Windows PowerShell!” he proudly declares with his hands on the BATCH module belt, standing heroically. First, we must ensure the firewall service is started on all of these systems. We will get the status of it using the Get-Service cmdlet.”

GET-SERVICE “Windows Firewall”

“We can see on this machine that it’s stopped.”

Image showing Windows Firewall has stopped

“To restart it, we can pipe it into the Start-Service cmdlet.”

GET-SERVICE “Windows Firewall” | START-SERVICE

Cmdlet is rapidly opening up his copy of PowerGUI to begin building the script for rapid deployment.

“Now,” he mumbled as he gnawed on his cape, “to reset those home pages. Need to get this done fast.”

For a moment, he eyed a large cache of energy drinks and pictured Cmdlet running about like a gerbil clicking away on GUI options. He smiled.

“Nah! Let’s use the registry!” he thought aloud. “So to change these home pages and how he’s redirected the search, we’ll need to directly access the registry for each user. The settings we need are all under this key.”

“HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\”

Using Regedit, BATCHman shows Cmdlet an example of what Ping Win had done.

Image of editing string with Regedit

“And there are three values we need to fix: Start Page, Search Page, and possibly even Default_Page_Url. As you can see, Cmdlet, he’s modified Default_Page_Url to point to his own private dastardly site. But we can easily access the registry using Windows PowerShell. We can access the registry using a built-in provider. To get the list of available providers, we simply type this.”

GET-PSPROVIDER

“Holy convenience store, BATCHman! HKCU is marked as a drive! Do you mean if I were to type SET-LOCATION HKCU:, I would be navigating the registry?”

“Not only that but if you ran a GET-CHILDITEM against it, you would see that part of the registry: GET-CHILDITEM HKCU: Or we can even recurse: GET-CHILDITEM HKCU: –recurse.”

Cmdlet pauses in thought. “So to access the available registry keys for HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\ all I have to do is enter:

GET-CHILDITEM HKCU:\Software\Microsoft\Internet Explorer\Main\

BATCHman smiled. “Close, my little digital partner, but not quite. You would need to execute a GET-ITEM because that is how the registry tree branches are recognized by Windows PowerShell. The CHILDITEMs in this case are actually just other available branches under HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\. To see what is attached to the main branch, we type this.”

GET-ITEM HKCU:\Software\Microsoft\Internet Explorer\Main\

“And that shows us it has Properties attached to it.”

Image showing what is attached to branch

“To access and see what values are available under the main branch, we need only attach the property name, which oddly in this case is called Property, to the original line in Windows PowerShell.”

(GET-ITEM HKCU:\Software\Microsoft\Internet Explorer\Main\).Property

“Now if we need to pull down the values of a PROPERTY from an ITEM in the registry, we do this.”

GET-ITEMPROPERTY –path “Registry::HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main“

Cmdlet blinked as he saw all the registry values from the Main key appear on the screen. “Holy Bee Hive!” he muttered.

“Now of course if we need to see a particular value, such as say Default_Page_Url, we type this.”

GET-ITEMPROPERTY –path “Registry::HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main“ –name “Default_Page_Url”

“But BATCHman, you’ve forgotten the most important part! We need to fix them and fix them now! Kids are due to arrive in minutes!”

BATCHman realized he got a little too carried away in chatting about Windows PowerShell and had almost forgotten the task at hand. “Yes! Of course! So all we need to do to set the value in a key.”

SET-ITEMPROPERTY –path “Registry::HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main“ –name “Default_Page_Url” –Value “http://www.msn.com”

Cmdlet looked and took the initiative. “So for the remaining keys to put in some proper values, I need only do this?”

SET-ITEMPROPERTY –path “Registry::HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main“ –name “Start Page” –Value “http://www.msn.com”

SET-ITEMPROPERTY –path “Registry::HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main“ –name “Search Page” –Value “http://www.bing.com”

“Exactly! Now let’s save this script and try it on a machine!”

“But BATCHman! We need to alter their personal settings as well! How will we do that easily? And quickly?! We only have moments before the center opens!”

BATCHman thought about it. How to alter those settings automatically with this script? “Of course!” his fingers snapped, sending shockwaves. “We’ll use Group Policy and set it as a startup script! As they log in, it will overwrite all the mess Ping Win turned loose!”

BATCHman quickly navigated to the computer configuration and dropped in a reference to his script in the SYSVOL share. Soon, people began to arrive. They logged in. Nobody noticed anything odd.

Ping Win began to recover from his trip over the chords. He looked. No disgusted reactions. Happy people. “Meeeeeea! FOILED!” he screamed and fell over another power cord.

“Cmdlet,” the BATCHman said watching Ping Win “Next time, let’s avoid buying the arch villain a big neon sign he can trip over. We could have spent that money on tires for the WinMobile”

 

Sean, thanks for another awesome episode of BATCHman. Everyone, join us tomorrow for Episode 6.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

 

 

BATCHman Uses PowerShell to Import a CSV File into His SQL Server

0
0

Summary: Windows PowerShell superhero BATCHman quickly imports CSV data into his SQL Server.

 

Microsoft Scripting Guy Ed Wilson here. Sean Kearney is back today with Episode 6 of the BATCHman series.

Note   You can read all gripping, engaging, informative, and downright funny BATCHman episodes.

 

BATCHman and Cmdlet logo

Whenever trouble happens in systems and people will call,
and darkness rolls out causing your fall,
Creatures of bits roam in the night,
Shine to the sky, the bright bluish light,

and call to…BATCHman !

…and, oh yes, his sidekick Boy Blunder Cmdlet, too.

 

In Today’s Episode, BATCHman Encounters Cmdlet’s Bad Field Notes!

So after a long week of crusading, standing on Telephones, being blinded by overcharged BATCHsignals, and generally keeping those ne’er-do-well evildoers at bay, BATCHman and Cmdlet are now about to upload all of Cmdlet’s notes to the BATCHcomputer. (No, forget that thought. It does not BATCH process with COBOL!)

“So, Cmdlet, let’s get those notes off your local SQL Express database and merge them from the Batch applet I created for taking field notes. Time to compile some data!”

“Uhhhh,” is Cmdlet’s only response. “What’s a Batch applet?”

BATCHman stands there scratching thoughtfully on his chin. “Why that would be the application I provided to you to keep field notes about all those evil villains we planned to encounter. I wrote it specifically to just simply sync up with the SQL 2008 R2 batch database on the batch computer.”

Cmdlet shuffled his feet. “Sooooo, not the batch Excel sheet?”

A pause of realization. “No.”

More shuffling by our Boy Blunder. “So, not Notepad? Not the XML editor?”

BATCHman just stood there. His beautiful applet, enabled with Windows PowerShell cmdlets, the GUI written with PrimalScript with some tweaking from PowerBoots. And it has gone unused.

"Cmdlet, can I see your notes?”

Boy Blunder hands over his Slate PC to BATCHman. Quickly, BATCHman keys into Windows PowerShell.

GET-CHILDITEM $HOME\Documents\CmdletNotes

The output produces some dismay to the BATCHman.

BADGUYS.CSV

“A CSV file?”

“Well, we were in the heat of battle, and I just quickly grabbed what was available to me. I thought it would be easy to search and sort and I…I…OH PLEASE! PLEASE BE MERCIFUL! PLEASE DON’T DECOMPILE ME!!!” Cmdlet wailed

BATCHman shook his head with a smile and tapped his young friend gently on the shoulder. “It was a mistake and an honest one. But remember, we have Windows PowerShell. We just need to convert this data into something the batch database will recognize. So let’s take a quick look at your CSV file.”

IMPORT-CSV BADGUYS.CSV

Image of CSV file contents

“Well this isn’t so bad. All we need to do is match these fields with ones from the BATCHman database. Because Windows PowerShell will work with SQL, we could literally import your CSV file into the database. First, we’ll add the SQL snap-ins to allow us to work with SQL Server from Windows PowerShell.”

ADD-PSSNAPIN SqlServerProviderSnapin100
ADD-PSSNAPIN SqlServerCmdletSnapin100

“With these added we can use Invoke-SQLCmd, which will allow us to pass SQL queries directly from Windows PowerShell, returning the results as an object. As an example, here is our current query. Because this is a small database, we’ll just use this. This presumes that the user, me in this case, has access.”

Invoke-Sqlcmd -Query 'SELECT * FROM BATCHmanDB.dbo.BATCHmanCrimeTable' -ServerInstance localhost

Cmdlet looked as the output appeared on the screen. You could tell by the single row of data they were very early into the crime fighting game, and BATCHman started at an early age.

Image of query output

“But BATCHman? How does this help us? All this did was show us information in a SQL database! We need to take my data and place that in SQL! Oh please! Just let me retype it!”

BATCHman smiled. “Because little buddy, this is a Windows PowerShell object. I can do this, too.”

$DATA=(Invoke-Sqlcmd -Query 'SELECT * FROM BATCHman.dbo.BATCHmanCrimeTable' -ServerInstance localhost)

$DATA.CriminalName

Cmdlet looked and realized he was now looking at an object in Windows PowerShell as normal. A light lit in his eyes.

“Wait! Do you mean I could put Windows PowerShell objects in an SQL query and populate the BATCHman database?”

“Exactly!” decried BATCHman, nearly poking Cmdlet in the eye. So first, let’s look at your file. It appears Villain will be the same as Criminal Name, Appearance matches Description, but the other two are dead on the nose. There are some fields you don’t have, such as Solved, but these are not required in the database. We can edit these later if we choose. Our only challenge now is to build the query.”

BATCHman pulled open his slate and launched SQL Server Management Studio.

“A very simple SQL INSERT query to add a row to the BATCHman database would look like this.”

INSERT INTO [BATCHmanDB].[dbo].[BATCHmanCrimeTable]
([CriminalName],[Description],[Problem],[Solution])
VALUES
(‘SomeEvilGuy’,’Looks Awful Funny’,’Something bad’,’Something Good’)
GO

“We can easily make this a value in Windows PowerShell like this,” BATCHman noted.

$SQLQUERY=”INSERT INTO [BATCHmanDB].[dbo].[BATCHmanCrimeTable] ([CriminalName],[Description],[Problem],[Solution]) VALUES (‘SomeEvilGuy’,’Looks Awful Funny’,’Something bad’,’Something Good’)”

The eyes of Cmdlet opened wide. “BATCHman! That’s almost unreadable! Couldn’t I just do this?”

$SQLHEADER=”INSERT INTO [BATCHmanDB].[dbo].[BATCHmanCrimeTable] ([CriminalName],[Description],[Problem],[Solution])“

$SQLVALUES=”VALUES (‘SomeEvilGuy’,’Looks Awful Funny’,’Something bad’,’Something Good’)”

$SQLQUERY=$SQLHEADER+$SQLVALUES

BATCHman beamed. “Excellent! You’ve been learning well. Now let’s take your notes and begin importing them into the database. We could just write it in a single line, but let’s take it one piece at a time. Let’s store your CSV file in a variable.”

$DATA=IMPORT-CSV BADGUYS.CSV

“Now we’ll step through each line with a Foreach-Object.”

FOREACH ($LINE in $DATA)

{
$Criminal=$Line.Villain
$Description=$Line.Appearance
$Problem=$Line.Problem
$Solution=$Line.Solution

}

Cmdlet watched the CSV flow on the screen. “So, BATCHman, can we just substitute the Windows Powershell variables for the same samples in the query?”

BATCHman nodded. “With one exception: we need to make sure the single quotes are still surrounding the data because the SQL query is expecting them. So we will populate the values like this, remembering the quotation mark is a special character and will need an escape before each reference.”

$Criminal="`'"+$Line.Villain+"`'"
$Description="`'"+$Line.Appearance"`'"
$Problem="`'"+$Line.Problem"`'"
$Solution="`'"+$Line.Solution"`'"

“So we can now just replace them in the query? Do you mean like this?” Cmdlet quickly edits the query lines.

$SQLHEADER=”INSERT INTO [BATCHmanDB].[dbo].[BATCHmanCrimeTable] ([CriminalName],[Description],[Problem],[Solution])“

$SQLVALUES=”VALUES ($Criminal,$Description,$Problem,$Solution)”

$SQLQUERY=$SQLHEADER+$SQLVALUES

“Correct, now we drop that into our script so that we end up with this.”

$DATA=IMPORT-CSV BADGUYS.CSV

FOREACH ($LINE in $DATA)

{
$Criminal="`'"+$Line.Villain+"`'"
$Description="`'"+$Line.Appearance+"`'"
$Problem="`'"+$Line.Problem+"`'"
$Solution="`'"+$Line.Solution+"`'"

$SQLHEADER=”INSERT INTO [BATCHmanDB].[dbo].[BATCHmanCrimeTable] ([CriminalName],[Description],[Problem],[Solution])“

$SQLVALUES=”VALUES ($Criminal,$Description,$Problem,$Solution)”

$SQLQUERY=$SQLHEADER+$SQLVALUES

Invoke-Sqlcmd –Query $SQLQuery -ServerInstance localhost

}

They executed the script, quickly populating the BATCHman database with the needed data. Cmdlet wiped the sweat off his face with a pair of Vibram shoes he found by the door.

“No sweat, little buddy. With Windows PowerShell, almost any problem can be eliminated. Now, let me show you the cool features for taking your notes.”

 

Sean, many thanks for sharing these episodes of BATCHman. Everyone, join us tomorrow as guest blogger Thiyagu talks about Exchange Best Practice Analyzer XML Parser.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

 

 


A PowerShell Exchange Best Practices Analyzer XML Parser

0
0

Summary: In this guest blog post, you will learn how to create a Windows PowerShell parser to parse the XML file generated using ExBPAcmd.exe.

 

Microsoft Scripting Guy Ed Wilson here. I want to welcome our Guest Blogger Thiyagu again today. Here is a little about Thiyagu:

I am the founder of the Singapore PowerShell User Group. I am an Exchange administrator, and I have been scripting for more than seven years now. Before Windows PowerShell, I did most of my scripting in VBScript. With Windows PowerShell, I automate Exchange/Active Directory tasks, and I am also good at WMI, ADSI, and generating custom reports. I have developed custom applications in C# for automation. I love to automate things! You will find me on my blog.

Photo of Thiyagu

 

What Is the Best Practices Analyzer?

The Best Practices Analyzer (BPA) is a server management tool that is available in Windows Server 2008 R2. BPA can help administrators reduce best practices violations by scanning one or more roles that are installed on Windows Server 2008 R2, and reporting best practices violations to the administrator. Administrators can filter or exclude results from BPA reports that they don’t need to see. Administrators can also perform BPA tasks by using either the Server Manager GUI, or Windows PowerShell cmdlets.

BPA is part of the Windows Server 2008 R2, and you can run it on most of the roles installed on the server.

The following list includes some of the roles against which you can run BPA:

  • Active Directory Domain Services
  • Active Directory Certificate Services
  • Domain Name System (DNS) Server
  • Remote Desktop Services
  • Web Server (IIS)
  • Active Directory Rights Management Services (AD RMS)
  • Application Server
  • DHCP
  • File Services
  • Hyper-V
  • Network Policy Server (NPS)
  • Windows Server Update Services (WSUS)

You can use the following Windows PowerShell cmdlets to work with the various Best Practices Analyzers:

  • Get-BPAModel
  • Get-BPAResult
  • Invoke-BPAModel
  • Set-BPAResult

Read more about BPA cmdlets.

But today’s topic is about the Exchange BPA, and we cannot run those cmdlets against Exchange. Instead, Exchange 2010 has its own ExBPA installed with it. I will explain how you can use Windows PowerShell to automate this. Here is how the GUI looks.

Image of ExBPA interface

You can use the GUI to scan a given set of servers and specify the type of scan, and this will do all the work for you. But as an Exchange Administrator, you should be doing this on a weekly or monthly basis. So here is how you can do this in an automated way.

In the build, there is an executable that comes with ExBPA called ExBPACmd.exe, which is kind of the command line version of the GUI. Here are some of the important parameters for the ExBPACmd.exe:

-dat <file>  Write the output data to <file>.  The default is

               output.<label>.<timestamp>.xml in the exbpa output directory.

 

  -d <server>  Access the directory using the global catalog server <server>.

               If not given, it will bind to the nearest one.

  -r <option>[=<value>][,...]

               Restrict the collection/analysis to include the specified

               restriction.  The default is "Health Check".

Here are the valid restriction options:

Scope: Server,AdminGroup,Organization,Domain,ADC Server,_

Role:

Mailbox,Gateway,Bridgehead,ClientAccess,UnifiedMessaging,Global,AdminTools,LanguagePacks,UmLanguagePack

Task: Health,Perf,Permissions,UserPermissions,ConnectivityTask,BaselineTask,PrecheckInstall,PrecheckUninstall,PrecheckUpgrade,PrecheckDR,Postcheck

Level: 1,2,3,4,5

Category:

General,Performance,Security,EndUserPermissions,Connectivity,Baseline,

CustomBaseline,Prereqs

 

Here is a sample command:

ExBPACmd.exe -dat test.xml -r "Health,5,Server=Van-EX1"

The preceding command will start an ExBPA scan type of health and level 5 and on server “Van-Ex1”; it will output the data to test.xml. You can put this command in your little script and call the program from within Windows PowerShell. You should then finally end up having the XML file. Now the fun stuff starts.

Here is what the XML looks like when you view it using ExBPA.

Image of how the XML looks when viewed in ExBPA

Each of these entries is present in the XML file and we have to get them out. Here is a sample of one of those items from the XML piece:

<Message Name="fDiskDriverAgeWarning"

Query="get-days(date-difference($dCurrentDateTime/Result, (date-parse(substring(($_/../Value | $_/../Instance),1,8), 'yyyyMMdd')))) &gt;730"

Error="Warning"

Title="Storage driver is more than two years old"

Text="Storage driver file '{5}' for '{1}' on server {2} is more than two years old. Check with your vendor to find out if a newer version is available. Installed driver details: {6} - {8}"

P1="LSI Adapter, SAS 3000 series, 8-port with 1068"

P2="VAN-EX1.Adatum.com"

P5="c:\windows\system32\drivers\lsi_sas.sys"

P6="1.28.3.52" P8="20090714094804.350065+480"

EventID="2408" Pass="True">

 

Storage driver file 'c:\windows\system32\drivers\lsi_sas.sys' for 'LSI Adapter, SAS 3000 series, 8-port with 1068' on server VAN-EX1.Adatum.com is more than two years old. Check with your vendor to find out if a newer version is available. Installed driver details: 1.28.3.52 - 20090714094804.350065+480

</Message>

 

I just formatted the XML code so that it is more readable. Notice that there are different attributes for the Message node. Here are the ones on which we will focus:

  1. Error
  2. Title
  3. Text
  4. P2
  5. P3
  6. InnerText

It is so easy to parse XML with Windows PowerShell, and within two lines, you can get what you need:

$xmlFile = [xml](Get-Content test.xml)

$parseddata = $xmlFile.SelectNodes("ObjectCollector//Message")

 

The first line gets the content of the test.xml file and turns it into XML. You can see this with Get-Member.

Image of first line of text.xml being turned into XML

 

On the next line, I use a method of the System.Xml.XmlDocument called SelectNodes. You can read more about this method. The idea is that you can pass an XPath Expression, which is a way of narrowing down what you want out of the XML file. In this case, I am passing the string, ObjectCollector//Message. The first two lines of the XML are shown in the following figure.

Image of first two lines of the XML

The root node is called ObjectCollector, so the first of the string is saying start the search from the root. The // means give me all the nodes from ObjectCollector onward, which are called Message. What we get out of the next line of code is a collection of XML elements. See the image below for details of the XMLElement object.

Image of details of XMLElement object

Each of the elements has an attribute called Error, and they have six possible options:

  • Error
  • Warning
  • None (which means Information)
  • NonDefault
  • Baseline
  • BestPractice

You can pipe the data to Where-Object and filter on the desired output. The following command returns only warning messages:

$parseddata | Where-Object {$_.Error -eq "Warning"}

With this in mind, I created an advanced function that accepts two input parameters: InputFileName and InformationType. The function returns the matching XML element objects out to the pipeline. You pipe the output from the advanced function to the ConvertTo-HTML cmdlet and then use the Send-Mailmessage cmdlet has a report sent to your mailbox.

Add a scheduled task to do this periodically and you are good to go. No need to manually run the GUI again for this:

.\Parse-XML.ps1 -InputFileName .\ExBPA.xml | ConvertTo-Html | Out-File “ExBPAReport.HTML”

Download the complete script from the Script Center Script Repository.

 

Thank you, Thiyagu, for once again sharing your knowledge. I love the way that you wrap up with your function and suggestion for creating a scheduled task to generate a report. Cool.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

 

 

Learn How to Save PowerShell Objects for Offline Analysis

0
0

Summary: Learn how to use Windows PowerShell to save objects for later offline analysis.

 

Hey, Scripting Guy! QuestionHey, Scripting Guy! I have a problem. I am trying to examine processes that are consuming resources on my computer. The problem is that when I use the Get-Process cmdlet, my results keep changing before I have a chance to examine thoroughly the output from my last output. I would like a way that I could store the command, and then analyze the results at my leisure. I know I can write to a text file, but I like having an object with which to work. In addition, I know that I can store the results in a variable, but I am a one person IT department at my company. I often have to leave my desk for extended periods of time, which means I cannot leave Windows PowerShell running all the time. What can I do?

—BH

 

Hey, Scripting Guy! AnswerHello BH,

Microsoft Scripting Guy Ed Wilson here. I record two sessions for TechNet Radio this afternoon. I am beginning a series of monthly podcasts in which I will be discussing Windows PowerShell best practices. Of course, part of the discussion springs from my Microsoft Press book, Windows PowerShell 2.0 Best Practices, but other things discussed derive from things I saw during the 2011 Scripting Games, as well as questions I have received as the Scripting Wife and I have traveled around speaking at various conferences. Indeed, one of the best things about being the Microsoft Scripting Guy is the ability to talk to passionate people who are striving to use Windows PowerShell to solve real-world problems.  

One of the things that is really cool about Windows PowerShell is the way it makes working with processes so easy. On my antique laptop, I am very concerned with processes because they eat up precious memory resources, and they drain my aged battery of its limited life. I know I am not the only one in the world who faces restrictions in IT spending; luckily, Windows PowerShell provides a razor sharp tool that allows one to hone in on errant processes.

BH, as you pointed out, it is easy to write process information to a text file. To do this, I use the redirection arrows from inside the Windows PowerShell console. I like to use the alias gps when working with the Get-Process cmdlet from console. The complete command to get all of the process information and write it to a text file is shown here:

gps >>

c:\fso\gps.txt

The output that is stored in the text file is shown here.

Image of output stored in text file

Depending on what you are attempting to accomplish, having a nicely formatted text file may just do the trick. On the other hand, if more than limited searching and perusal are in the forecast, a text file quickly outlasts its welcome.

Of course, I can store the results of the command in a variable, and use all the power of Windows PowerShell to parse the data. For example, I can store my process information in a variable, and then sort the processes based on the amount of CPU time the processes are using. In the command that follows, I use the variable $gps to hold the process information that is retrieved by the Get-Process cmdlet. On the second line of the command, I pipe the System.Diagnostics.Process objects to the Sort-Object cmdlet (sort is an alias). I tell the Sort-Object cmdlet that I want to sort on the cpu property and I want that sort to be a descending sort (the biggest numbers on top). These two commands are shown here:

$gps = Get-Process

$gps | sort cpu –Descending

The following figure contains both the commands and the output associated with those commands.

Image of commands and associated output

So it is easy to work with process objects in an offline fashion, as long as Windows PowerShell is kept running and the value stored in the $gps variable does not become overwritten. If I need to shut down Windows PowerShell or to reboot my computer, how can I continue to access the same process objects? I use the Export-Clixml cmdlet. I know the name of the cmdlet is a bit confusing, and for some it is downright scary. After all, most network administrators are skittish when it comes to XML.

The cool thing about using the Export-Clixml cmdlet is that you do not need to know anything about XML to use it. All I am doing when I pipe my process information to the Export-Clixml cmdlet is using XML to store a representation of my objects. XML is the perfect choice for this. XML is a rich data store that easily adapts my objects for offline use. The command itself is simplicity and elegance personified. To obtain all the process information, I use the Get-Process cmdlet (gps is an alias), and I pipe the results to the Export-Clixml cmdlet. I provide the Export-Clixml cmdlet with a path to store the resultant XML file. This command is shown here:

gps | Export-Clixml c:\fso\gps.xml

The resultant XML file is an actual XML file and is therefore viewable in an XML viewer, as shown in the following figure.

Image of XML file in an XML viewer

After I have an XML representation of my process objects, I can import the XML file and work with the objects at any time in the future. I can reboot my computer 100 times, and still be able to open Windows PowerShell and view my offline process objects. In fact, I can use the XML file on a different computer if I need to do so.

To import the XML for use on my computer, I use the Import-CliXML cmdlet. It only needs the path to the XML file. I can store the resultant process objects in a variable for ease of processing. In the following series of commands, I use the Get-Process cmdlet (gps is an alias) to retrieve process information. I pipe the objects to the Export-CliXML cmdlet and provide it with a path to store the resulting XML file. I then use the Import-CliXML cmdlet to import the XML file and store the process objects in the $gps variable. Next, I pipe the process objects to the Where-Object cmdlet (? Is an alias for Where-Object) where I look for process names that match word. The commands that accomplish all this are shown here:

gps | Export-Clixml c:\fso\gps.xml

$gps = Import-Clixml C:\fso\gps.xml

$gps | ? { $_.name -match 'word' }

The commands and associated output are shown in the following figure.

Image of commands and associated output

I do not have to store the imported XML in a variable. I can simply use Import-CliXML and pipe the results directly into other Windows PowerShell cmdlets for processing. For example, if I want to look for duplicate processes that are running, I might import the XML file, group (alias for the Group-Object cmdlet) the processes on the name property, and sort (alias for the Sort-Object cmdlet) the results based on the count property in a descending fashion. The command that accomplishes this is shown here:

Import-Clixml C:\fso\gps.xml | group name -NoElement| sort count -des

The command and associated output are shown in the following figure.

Image of command and associated output

One thing to keep in mind when working with Import-CliXML and Export-CliXML is that the created objects are deserialized. This means that the methods normally available to the System.Diagnostics.Process objects are not available. Other than that, they look and behave exactly like normal objects. I can pipe the XML to the Get-Member object to see what is available and what is not available. The command to do this is shown here:

Import-Clixml C:\fso\gps.xml | get-member

The command and associated output are shown here.

Image of command and associated output

 

Well, that is about all there is to working with offline objects and utilizing the Import-CliXML and Export-CliXML cmdlets. Join me tomorrow for more exciting Windows PowerShell stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

 

 

Use PowerShell to Work Easily with Drives and Paths

0
0

Summary: Learn how to use Windows PowerShell drives to simplify access to complex data storage paths.

 

Hey, Scripting Guy! QuestionHey, Scripting Guy! I like using PSDrives. Unfortunately, a problem I have is that I never really know where I am at in the hierarchy. For example, if I am on my fso drive, where does that drive happen to be? Can you provide me with some special Scripting Guy tricks to help me with this problem? I earnestly await your reply.

—CL

 

Hey, Scripting Guy! AnswerHello CL,

Microsoft Scripting Guy Ed Wilson here. I recently made a presentation for a group of Windows PowerShell enthusiasts, and one of the things I showed them was the concept of PSDrives. In fact, I think it is one of the revolutionary concepts that are exposed by Windows PowerShell. The ability to use the same Windows PowerShell cmdlets to work with disparate data sources is simply amazing. That I can use Get-ChildItem and retrieve a list of registry keys, certificates, files, folders, variables, aliases, and environmental variables makes Windows PowerShell truly a power(ful) shell.

I love creating custom PSDrives to simplify access to my Hey, Scripting Guy! Blog posts and scripts. To do this, I use the New-PSDrive cmdlet, specify the name of the provider (filesystem), and provide it with the name of the drive and the path to the root of the new drive. Here is the command I use on my laptop to create my special HSG drive:

New-PSDrive -PSProvider filesystem -Root C:\data\ScriptingGuys\2011 -Name hsg

When the command runs, it returns information about the newly created drive. The information is contained in the PSDriveInfo object that is shown here:

14:39:01 C:\> New-PSDrive -PSProvider filesystem -Root C:\data\ScriptingGuys\2011 -Name hsg | gm

 

   TypeName: System.Management.Automation.PSDriveInfo

 

Name                           MemberType                 Definition

CompareTo                   Method                         int CompareTo(System.Management.Automation.PSDriveInfo drive), in...

Equals                           Method                         bool Equals(System.Object obj), bool Equals(System.Management.Aut...

GetHashCode                Method                         int GetHashCode()

GetType                        Method                         type GetType()

ToString                        Method                         string ToString()

Credential                     Property                        System.Management.Automation.PSCredential Credential {get;}

CurrentLocation             Property                        System.String CurrentLocation {get;set;}

Description                    Property                        System.String Description {get;set;}

Name                           Property                        System.String Name {get;}

Provider                        Property                        System.Management.Automation.ProviderInfo Provider {get;}

Root                             Property                        System.String Root {get;}

Free                              ScriptProperty               System.Object Free {get=## Ensure that this is a FileSystem drive...

Used                             ScriptProperty               System.Object Used {get=## Ensure that this is a FileSystem drive...  

 

After I have created my new PSDrive, I can change my working directory location to that drive. By changing my working directory, I gain easy access to the files and folders in that location. To change location to a new drive, I can use the Set-Location cmdlet and provide it with the name of the new PSDrive. In addition, to using the cmdlet name directly, there are three aliases that can also be used from the command line: cd, chdir, and sl. The following command uses the alias cd to change the working location to the hsg PSDrive. The Windows PowerShell prompt changes to reflect the new location (I have a custom Windows PowerShell prompt that displays the current time as well as the current location):

14:56:50 C:\> cd hsg:

14:57:44 hsg:\>

If I want to return to the C: drive, I can once again use the cd alias:

14:57:44 hsg:\> cd c:

15:00:31 C:\>

I use the up arrow to retrieve my previous command and return to the HSG drive. When I am on my HSG drive, I can use the Get-Location cmdlet to retrieve my current location. The default view returns only the path, as shown here:

15:03:30 hsg:\> Get-Location 

Path

----

hsg:\

Okay, I will admit the default is basically useless when working interactively from the Windows PowerShell console because the default Windows PowerShell prompt includes the current location. However, as with everything else in Windows PowerShell, the Get-Location cmdlet returns an object. This means there are additional properties and methods that are available. A quick use of the Get-Member cmdlet shows me there are some interesting properties that could be helpful. The command to retrieve the members from the PathInfo object is shown here along with the associated output:

15:04:14 hsg:\> Get-Location | gm 

TypeName: System.Management.Automation.PathInfo

 

Name                           MemberType                 Definition

Equals                           Method                         bool Equals(System.Object obj)

GetHashCode                Method                         int GetHashCode()

GetType                        Method                         type GetType()

ToString                        Method                         string ToString()

Drive                             Property                        System.Management.Automation.PSDriveInfo Drive {get;}

Path                              Property                        System.String Path {get;}

Provider                        Property                        System.Management.Automation.ProviderInfo Provider {get;}

ProviderPath                  Property                        System.String ProviderPath {get;}

 

The property that looks interesting to me is the ProviderPath property. To see if this will help me to resolve the actual path to the PSDrive, I pipe the output to the Format-List cmdlet. The command and associated output are shown here:

15:04:20 hsg:\> Get-Location | fl *

 

Drive:                hsg

Provider:           Microsoft.PowerShell.Core\FileSystem

ProviderPath:     C:\data\ScriptingGuys\2011\

Path:                 hsg:\

 

Because the ProviderPath is a property of the PathInfo object, it means I can access it directly by using a dotted notation. The command to display only the value contained in the ProviderPath property is shown here along with the associated output:

15:04:32 hsg:\> (Get-Location).providerpath

C:\data\ScriptingGuys\2011\

The Convert-Path cmdlet knows how to convert a PSDrive for a file system location to the actual path to that filesystem location. In the following command, I use the Convert-Path cmdlet to convert the path to the HSG: drive:

15:17:20 hsg:\> Convert-Path -Path HSG:

C:\data\ScriptingGuys\2011\

It might be possible that I do not know where my actual working directory resides—or even what it is. This may be the situation when running inside a script. I can therefore use the Get-Location cmdlet to find out where my current working directory resides, and pass it to the Convert-Path cmdlet. The command and the associated output are shown here:

15:20:19 hsg:\> Convert-Path -Path (Get-Location)

C:\data\ScriptingGuys\2011\

If I am looking for PSDrives, I can use the Get-PSDrive cmdlet. If I do not supply any parameters, it will return all of the PSDrives on the system. However, because I am only concerned with PSDrives that are associated with the filesystem, I can specify that I only want PSDrives from the filesystem PSProvider. The command to return only PSDrives that are associated with the filesystem PSProvider is shown here:

Get-PSDrive -PSProvider filesystem

The command and associated output are shown in the following figure.

Image of command and associated output

When switching working locations, I like to use the Push-Location cmdlet (alias is pushd) and Pop-Location (alias is popd) to store my current location, switch to another location, and then return to the previous location. As a simple example, I am going to store my current location (current c:\), change the working location to the HSG: drive, get a directory output, and then return to my original location (c:\). Here are the commands that accomplish these tasks:

Push-Location

Set-Location hsg:

Get-ChildItem

Pop-Location

In the following figure, I use aliases to accomplish these tasks. The figure includes the commands and the associated output.

Image of commands and associated output

As long as I am talking about Windows PowerShell cmdlets that help in working with paths and locations, I may as well talk about the Resolve-Path cmdlet. It is cool and very powerful when working at the Windows PowerShell console. It allows me to use wildcard characters in path names, and it will resolve the path and output all the paths that match the wildcard character pattern. An example of this technique is shown here:

15:58:30 C:\> Resolve-Path c:\da*\*\*11

 

Path

C:\data\BookScripts_VbScript\ch11

C:\data\Presentation\RoadToTechEd_2011

C:\data\Presentation\TechReady_2011

C:\data\ScriptingGuys\2011

The output from the Resolve-Path cmdlet returns the same PathInfo objects that were returned earlier. This means that I can use the Where-Object cmdlet to find only paths that are related to scripting. This command is shown here (? Is an alias for the Where-Object cmdlet):

Resolve-Path c:\da*\*\*11 | ? { $_.path -match 'scripting'}

I could even send the output to a ForEach-Object cmdlet and use the Get-ChildItem cmdlet to query each of the returned paths. The command to perform this action is shown here (the % symbol is an alias for ForEach-Object and gci is an alias for Get-ChildItem):

Resolve-Path c:\da*\*\*11 | ? { $_.path -match 'scripting'} | % {gci $_.path}

 

CL, that is all there is to working with paths and PSDrives in Windows PowerShell. Thank you for your question, and I invite you to join me for more cool stuff with Windows PowerShell.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

 

 

Use PowerShell to Pick Random Winning Users from Text

0
0

Summary: Learn how to use Windows PowerShell to select random winners from a text file.

 

Hey, Scripting Guy! QuestionHey, Scripting Guy! I have a question. It is neither a vital server performance issue nor is it a dramatic process optimization revelation, but it is something that will make my life a lot easier. First the background: I have been going to our local IT user group for a while, and one of the members wrote a command-line application that would accept a text file that contained our attendees for the night. Well, that member recently moved to another city, and now we are in desperate need of something that will do a random drawing for us for our prize giveaways that we have at each meeting. I guess I could send email to the departing member and ask for the command-line application, but I have been preaching Windows PowerShell for so long that I sort of feel like I should create the solution in Windows PowerShell. But I need a bit of help doing that. Do you have any ideas for doing a random sort on a text file?

—CS

 

Hey, Scripting Guy! AnswerHello CS,

Microsoft Scripting Guy Ed Wilson here. Good afternoon, CS. During the 2011 Scripting Games, I wrote a script to perform a random sort of people who had submitted scripts during the event. I was doing daily drawings, and I also needed to exclude people who had previously won a prize, so my script is a bit overkill for what you need to do.

I was talking to someone the other day about this very thing. What my friend had done was rather clever. He said that he created a hash table with the key as the data to sort, and the value as a random number produced via the Get-Random cmdlet. He then used the getenumerator method from the hash table and piped it to the Sort-Object cmdlet to sort the hash table based on the random numbers. This has the effect of randomizing the list of user group names. I thought it was a clever approach to the problem, so I wrote the RandomSortUsersViaHashTable.ps1 script. The complete text of the script is shown here:

$users = Get-Content C:\fso\UserGroupNames.txt

$hash = @{}

foreach ($u in $users)

 {

  $hash.add($u,(Get-Random -Maximum $users.count))

 } #end foreach

 

$hash.GetEnumerator() | Sort-Object -Property value |

Select-Object -First 5

 

The first thing I do is use the Get-Content cmdlet to read the contents of the user group list into an array of user names. Next, I create an empty hash table, and store it in the $hash variable. I then use the foreach statement to walk the array of user names. This portion of the script is shown here:

$users = Get-Content C:\fso\UserGroupNames.txt

$hash = @{}

foreach ($u in $users)

Inside the ScriptBlock for the foreach statement, I use the add method to add the user name and a random number to the hash table. One thing to note: I limit the random number to the maximum number of users that are listed in the UsergroupNames.txt file. There is no real need to do this because I am later going to use the Select-Object cmdlet to choose the first five users anyway. Here is the line of code that adds the user names and the random number to the hash table:

$hash.add($u,(Get-Random -Maximum $users.count))

I then use the getenumerator method from the hashtable object, and pipe the hashtable to the Sort-Object cmdlet where I sort the hashtable based on the value of the random number. Finally, I choose five people from the hashtable. This portion of the script is shown here:

$hash.GetEnumerator() | Sort-Object -Property value |

Select-Object -First 5

When the script runs, the output shown in the following figure is displayed.

Image of output displayed when script is run

While the approach is valid and makes for a relatively cool script, there is a simpler way to accomplish the task of grabbing user names in a random fashion from a text file. In fact, the nine-line script boils down to a single line. In the following command, I use the Get-Content cmdlet (gc is an alias) to read the contents of the UserGroupNames.txt file. I pipe the results to the Sort-Object cmdlet and use a script block to choose a random name from the text file stream. I then select the first five users.

gc C:\fso\UserGroupNames.txt | sort{get-random} | select -First 5

The command when run three times and the associated output are shown here.

Image of command run three times and associated output

Perhaps, the easiest way to do this is to use the Get-Content cmdlet to read the contents of the text file, and bypass the Sort-Object cmdet completely. I can tell the Get-Random cmdlet to return only five user names from the text file, so I do not really need to sort the list first. This command is shown here (gc is an alias for the Get-Content cmdlet):

gc C:\fso\UserGroupNames.txt | Get-Random -Count 5

I run the command a few times to check to see if it is returning different names. As shown in the following figure, it works.

Image showing command works

If I do not need to select only a certain number of users, I can use the Get-Random cmdlet to randomize the entire list by using the count property of the array to read the contents of the text file into a variable. Here is one way to accomplish this task:

$users = gc C:\fso\UserGroupNames.txt

Get-Random -InputObject $users -Count $users.Count

In the following figure, I read the contents of the text file into the $users variable, and then I supply it as an inputobject to the Get-Random cmdlet. I then use the Measure-Object cmdlet to count how many items are returned by the command. The figure is shown here.

Image of reading text file contents into $users variable

As seen in the following figure, the contents of the text file consist of 12 users. In addition, a comparison between the text file and the random output shows that the user names are in fact displayed in a random order.

Image of contents of text file with 12 users

If memory consumption is an issue, the command can be revised to take advantage of the pipeline. The revised command is shown here:

$users = gc C:\fso\UserGroupNames.txt

$users | Get-Random -Count $users.Count

 

CS, that is it for generating random user names from a text file. I invite you to join me tomorrow for another exciting episode of BATCHman.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

 

Ed Wilson, Microsoft Scripting Guy

 

 

Convert Hexadecimal to ASCII Using PowerShell

0
0

Summary: Superhero BATCHman defeats evil Hextor and converts hexadecimal to ASCII to retrieve passwords.

 

Microsoft Scripting Guy Ed Wilson here. Sean Kearney is back again, and this time he delivers Episode 7 of the BATCHman series.

 

Whenever trouble happens in systems and people will call,

And darkness rolls out causing your fall,

Creatures of bits roam in the night,

Shine to the sky, the bright bluish Light,

And call to…BATCHman !

…and, oh yes, his sidekick Boy Blunder Cmdlet, too.

 

In Today’s Episode, BATCHman Encounters HEXTOR the Encyptor!

Panic grips the city! A beacon cuts through the night! It’s the BATCHsignal!

“Beep! Beep! beep! Beep!” Cmdlet rolls over and executes the Get-Snooze script. It is naptime in the BATCHcave.

But not for BATCHman. He deftly grabs Cmdlet’s blanket and flips him into the air like a flapjack. “No time to waste! Evil is afoot! Quick! To the Winmobile!”

Cmdlet looks inside the BATCHbay and sees an empty parking spot.

“Uhhhh, BATCHman, where’s the Winmobile?” gesturing to a large empty rectangle of pavement.

BATCHman smacks his head . “D’oh! I forgot I shipped it out for a Mango upgrade! Whatever shall we do?”

“Holy, Big Ben! What horrible timing! Then to the BATCHsubway! Quick, grab the tokens!”

They disappear into the local mass transit system.

***Meanwhile in another part of the city***

“BAA FAA FAA FAA!” the evil villain cackles “BAA FAA FAA!”

Dressed in nothing but dark purple with a large hexagon for a symbol, the evil genius Hextor looks down upon the chaos that has become the local Redmond post office, smiling.

“BAA FAA FAA! All your passwords are belong to me! The systems are locked away. None of you will ever retrieve them! For I have encrypted everything in….HEXADECIMAL! BAA FAA FAAAA!”

The administrator looks shaken. Decoding hexadecimal! What a foul turn of events! “Oh if only BATCHman were here!”

As if by sheer luck, our fearless heroes stumble onto the scene, smelling vaguely of the subway.

Hextor looks at our heroes with disdain. “Nothing can save them. Not you or your silly bad acting sidekick! Everything is written in pure hexadecimal! BAA FAAA FAAA FAAAA!” he giggled madly

Cmdlet stares at Hextor’s copy of the user password list. Now written in hexadecimal, it seems impossible to decrypt. “Holy magic hexes, BATCHman! He wasn’t kidding!”

50 6f 73 74 61 6c 41 63 63 65 73 73 31 09 55 62 65 72 4c 33 33 74 50 40 73 73 77 30 72 64 0d 0a 53 75 70 65 72 76 69 73 6f 72 09 42 40 74 63 68 4d 40 6e 77 31 6c 6e 76 72 47 33 74 74 68 31 73 21 0d 0a 41 64 6d 69 6e 69 73 74 72 61 74 6f 72 09 21 4b 72 40 35 68 4e 62 75 52 4e 3f 0d 0a 50 6f 73 74 61 6c 41 63 63 65 73 73 32 09 42 75 61 68 21 48 41 3f 68 61 21 48 41 41 41 41 21 3f 21 0d 0a

“Why, foul villian, I believe you’re right. Nothing can solve this easily. Nothing that is,” BATCHman pauses dramatically with a finger in the air, “except Windows PowerShell!”

Hextor’s eyes open like flying saucers! “EEEEEEEEEEEEEEEEEEEEE! AAAAAAAAAA! BAAAAA! ” is all that escapes his mouth as he runs off hands in the air, immediately sensing defeat.

BATCHman looks over at Cmdlet. “In Windows PowerShell, we can easily convert binary, octal, decimal, and even hexadecimal. It is a native feature. We just need to leverage [CONVERT]. To quickly convert a number to hexadecimal, I would type this.

[convert]::tostring(12345,16)

“This will produce the following hexadecimal output.

3039

“To convert back to decimal, we specify that we’re converting to an integer and specify the base we’re converting from.”

[convert]::toint16(“3039”,16)

Which produces

12345

Cmdlet looked on. “Wow, BATCHman! But that doesn't help us. We need to convert those hexadecimal numbers to decimal and then convert them back to a real ASCII character! I don’t think we can convert a number to an ASCII character. That’s just lu…”

“Hold there, chum. We can do that as well in Windows PowerShell. We just need to type it as a [char]. When [char] is followed by any decimal number less than 256, it converts it to an ASCII character. We can even find the ASCII value of characters using the [BYTE] type like this.

[BYTE][CHAR]’a’

97

“To convert back, all we do is reverse the process.”

[CHAR][BYTE]97

a

Cmdlet looked at the string of hexadecimal numbers. “So if we convert these to decimal, we can just preface the result of each one with [CHAR][BYTE] and see its ASCII character? That sounds too easy.”

“You’ve got it on the nose, oh sidekick of mine! Now, the challenge is we need as easy way to split up those hexadecimal pairs to convert them. Any thoughts?”

The eager one claps his hands together “Split! Holy chopping board, BATCHman! We can take this data, drop it into a string, and run a split method based upon the spaces separating them!”

Cmdlet quickly sets up a simple variable in Windows PowerShell:

$HEXDATA=”50 6f 73 74 61 6c 41 63 63 65 73 73 31 09 55 62 65 72 4c 33 33 74 50 40 73 73 77 30 72 64 0d 0a 53 75 70 65 72 76 69 73 6f 72 09 42 40 74 63 68 4d 40 6e 77 31 6c 6e 76 72 47 33 74 74 68 31 73 21 0d 0a 41 64 6d 69 6e 69 73 74 72 61 74 6f 72 09 21 4b 72 40 35 68 4e 62 75 52 4e 3f 0d 0a 50 6f 73 74 61 6c 41 63 63 65 73 73 32 09 42 75 61 68 21 48 41 3f 68 61 21 48 41 41 41 41 21 3f 21 0d 0a”

$HEXDATA.Split(“ “)

“What next? I think you have the idea right!”

“Well, we could pipe this into ForEach and apply the [convert]::toint16() against each like this.”

$HEXDATA.Split(“ “) | FOREACH{ [CONVERT]::toint16($_,16)}

BATCHman rubs his hands together with glee as the decimal numbers pour down the screen. “Excellent, Cmdlet! Now with all the decimal numbers, you can just convert them to ASCII, right?”

The other half of the terrible twosome added the [CHAR][BYTE] to the output.

$HEXDATA.Split(“ “) | FOREACH {[BYTE][CHAR]([CONVERT]::toint16($_,16))}

His jaw dropped. “Oh, no, it’s just a long unreadable column of letters. I need to write it in a row.”

“Soooooo, what if we could write to the host with no new line? We can pass your data to the Write-Host cmdlet without dumping a line feed between each out like so.”

$HEXDATA.Split(“ “) | FOREACH {WRITE-HOST –object ( [BYTE][CHAR]([CONVERT]::toint16($_,16))) –nonewline }

Cmdlet stared in awe as the message on the screen converted back to ASCII.

PostalAccess1 UberL33tP@ssw0rd
Supervisor B@tchM@nw1lnvrG3tth1s!
Administrator !Kr@5hNbuRN?
PostalAccess2 Buah!HA?ha!HAAAA!?!

“Now, quickly get the credentials reset before Hextor strikes again!”

Quickly the credentials were reset and the Redmond post office was back online. The postmaster stepped out to shake their hands.

“Oh, BATCHman, thank you! How can we ever repay you now that you’ve returned our passwords to us?”

“No thanks necessary, but any chance you have a stamp? I have to mail this to my mother for her birthday.”

 

Thanks, Sean, for another awesome episode of BATCHman. Everyone, join us tomorrow for Episode 8.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

 

 

Use PowerShell to Manage Office 365

0
0

Summary: BATCHman battles The Consultant and uses Windows PowerShell to manage Office 365 easily.

 

Microsoft Scripting Guy Ed Wilson here. Sean Kearney brings us Episode 8 of the BATCHman series today.

 

Whenever trouble happens in systems and people will call,

And darkness rolls out causing your fall,

Creatures of bits roam in the night,

Shine to the sky, the bright bluish Light,

And call to…BATCHman !

…and, oh yes, his sidekick Boy Blunder Cmdlet, too.

 

In Today’s Episode, BATCHman Encounters the Evil of The Consultant

Oh, the times are dangerous and frightening. Somewhere in Redmond, a team of IT people is running about madly with their hands in the air.

“AIAHGIHAIGHIH!!! AIHAGHAHGHAGHIHI!!! We can’t manage anything! The sky is falling the sky is falling! Aihihighighighhghgi!!!!”

Panic (and apparently Henny Penny) has gripped them by the ears. The systems administrator is on the phone madly dialing BATCHman directly.

“BATCHman!!! BATCHman!!! You’ve got to help us!!! HURRY!!! AIGHAIHGHAHGHAH!!!!!”

“Certainly, why we’ll be happy to b…”

He is cut off by more screaming and the sound of breaking glass. “HURRY!!! HURRY!!! It’s all over!!! AIAGIHGAIH” *click*

The phone is dead. Cmdlet without blinking yells, “To the WinMobile!” Cmdlet takes off to the scene in a flash.

BATCHman is left behind to wonder how he should get there. Our hero, looking about scratching his head, finds the only alternate means of transport.

“Well, err,. to the BATCHunicycle!” as he deftly hops on and wobbles his way to the crime scene.

***A good while later***

BATCHman arrives. He sees Cmdlet. “For future reference, the sidekick does not drive the superhero car,” tapping Cmdlet on the nose. “You’ll take the BATCHunicycle home,” he grinned.

Cmdlet has in the meantime gathers the details. “Pretty evil situation. The IT staff came in over the weekend The Consultant migrated them to Office 365.”

BATCHman is puzzled. That doesn’t seem evil. That seems quite nice actually.

“I don’t think you’re getting it. Not *A* Consultant but *THE* Consultant. He walked in, migrated them, left a bill on the table and didn’t tell anybody his plans. They have no instructions or documentation.”

BATCHman suddenly realizes the issue. One of the nastiest, grungiest creatures on the planet simply called “The Consultant” had arrived on the scene. His claim to the evil world would be to improve infrastructure, bill clients, and then leave them with no documentation of what happened. Often doing it as a surprise launch on a weekend, his calling card was nasty: a hefty bill and a panicked IT staff on Monday morning.

However, today The Consultant has met his match. He outdid himself. He used Office 365, and BATCHman and Cmdlet were on the scene.

“Never fear, bring the IT staff in here. Let them know BATCHman is on the scene. We can solve all their woes with Windows PowerShell!”

Moments later, the mob of IT staff and one very frightened cat gather in the boardroom.

BATCHman looks at them. “Was there anything left behind? Other than the bill?”

Senior Systems Administrator Sue walks over. “Just this envelope with an ID/password and the words ‘Office 365’. Everything is running, but none of our existing systems seems to work for management. We need to create some new users as well as manipulate our existing distribution lists.”

BATCHman calmly strokes his chin. “Office 365, you say? Well, then, as long as you have credentials, we’re okay. For basic access, all we need to do is log on to office365.com with the provided credentials, and we can do everything from there. But never fear. We can use Windows PowerShell as well to manage the email.”

BATCHman quickly logs on with the provided user ID and password to the Web-based interface for Office365.com, showing them a basic management interface.

“Now, normally to create a user in Exchange, we might use the New-Mailbox or Enable-Mailbox cmdlets. But the process for Office 365 isn’t too difficult. The workflow is almost identical to Exchange because it’s just Exchange in a hosted environment. First, we add the needed modules. The first is the MSONLINE module, which we download from the Office 365 website.”

IMPORT-MODULE MSONLINE

“Next we provide the credentials to Windows PowerShell using Get-Credential and connect to the Office 365 web services. The UserPrincipalName or email address and password The Consultant left you are your credentials.”

$Cred=GET-CREDENTIAL
CONNECT-MSOLService -credential $Cred

“After this is done, we bring down the Exchange cmdlets using implicit remoting from the Office 365 server.”

$s = NEW-PSSESSION -ConfigurationName Microsoft.Exchange -ConnectionUri https://ps.outlook.com/powershell -Credential $Cred -Authentication Basic -AllowRedirection
$importresults=import-pssession $s

The IT team begins to breathe more clearly. They are not locked out and this is scriptable. Windows PowerShell and BATCHman have once again saved the day.

“After the cmdlets are installed, you’ll find that many of the abilities to add and remove distribution groups and memberships are identical to what you’re used to because it is just Exchange on the back end. To create a user, however, is slightly different. We must use the following cmdlet.”

NEW-MSOLUSER

“So all you’ll need to do to create users is use the previously cached credentials you stored in the $CRED variable and run the cmdlet like so. This is presuming an email address of evilconsultant@contoso.com, the first name of ‘Evil,’ and the last name of ‘Consultant.’”

NEW-MSOLUSER –userprincipalname ‘evilconsultant@contoso.com -DisplayName 'Evil Consultant' –Firstname ‘Evil’ –Lastname ‘Consultant’

“But BATCHman! Creating users is fine, but what do we do to delete them?! Usually that is coming down the line quicker than creating a user! We need to ensure that when our payroll application disables the staff member, it can still run our existing Windows PowerShell module!”

BATCHman smiled. “I concur that’s just as important, but never fear, Windows PowerShell is here!”

They pause as BATCHman quickly types.

REMOVE-MSOLUSER –userprincipalname ‘evilconsultant@contoso.com’

“There is also a web-based interface at office365.com to allow a richer interface to manage the accounts in the system. You’ll also find a plethora of online resources to aid in managing the system.”

The IT team breathes a sigh of relief. Although The Consultant changed their back end on them, automation is still here to aid them. Being in the cloud did not mean being left alone on the ground, thanks to Windows PowerShell.

“By the way, if you have the card of that particular villain, I’d like to pass it along to the Better Business Bureau.”

 

Thanks Sean for this episode of BATCHman. Join us tomorrow for another exciting episode of BATCHman—Episode 9!

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

 

 

BATCHman Uses PowerShell to Identify and Unlock User Accounts

0
0

Summary: BATCHman shows how to use Windows PowerShell to locate and unlock user accounts in Active Directory.

 

Microsoft Scripting Guy Ed Wilson here. In the continuing saga of the world’s first Windows PowerShell superhero, BATCHman, and his faithful sidekick, Cmdlet, I once again present Windows PowerShell MVP and Honorary Scripting Guy Sean Kearney.  

BATCHman and Cmdlet logo

Whenever trouble happens in systems and people will call,

And darkness rolls out causing your fall,

Creatures of bits roam in the night,

Shine to the sky, the bright bluish Light,

And call to…BATCHman !

…and, oh yes, his sidekick Boy Blunder Cmdlet, too.

 

Shock! Terror! The Redmond Police office has been rendered useless! A dark shadow has crossed over the LAN!

“Our accounts! Every account in Active Directory locked out!” the police chief stared blankly at the computer screen. He then glared darkly across the hallway at the culprit who is dressed in all black, hissing back at the police chief.

It was the dreaded Script Kitty, Madame CatFile’s only daughter. For years, there was a chance of her not assuming her mother’s role of foul villainry, and then the worst happened: she saw the cool clothes evil villains wore, and that was that. She was another victim of fashion.

Tonight, she had somehow slipped into the office in the guise of one of the cleaning staff and plugged her laptop into an unwatched LAN jack. She ran her “AttackCityHall.vbs” script in the hopes of unlocking at least one account. Fortunately for the city of Redmond and unfortunately for her, neither time nor password complexity rules was on her side.

Unfortunately, the city had for security reasons designed its Active Directory to not automatically unlock. Thus, the poor police chief found himself in a predicament.

“Hiiiiissssss,” Script Kitty hissed again at the chief.

How dare he walk in on her while she was attempting to hack all of the accounts in the city of Redmond? She would have gotten away, too, if it weren’t for that oh-so-cute little mouse. She just had to pounce on it! After all, it was a pink Arc mouse. “So rare! Purrrrr,” her mind raced and then she was quickly caught and locked up.

There was only one account that Script Kitty missed. She, in her haste, somehow overlooked an administrator account.

The police chief looked over at the blue box on the wall with a small hammer marked, “In case of network emergency, break glass and press button.”

The glass shattered, the police chief did the one thing he never thought he’d need to do: he summoned the BATCHman Klaxons.

He pressed the Get-Help button, and moments later, 1,000 loudspeakers inside his office began pumping out a 1,000-decibel warning siren along with a blinding light.

Covering his ears and eyes, he stumbled across the room looking at the deputy. Taking a hammer to the Get-Help button and many sparks later, the sound and light disappeared.

Staring at his deputy, he cursed, “I told you, have them mount the BATCHman warning system outside the office, not inside!” He quickly grabbed his cell phone and dialed BATCHman’s private line.

***Moments later with a THUD and WHUMP***

“Never fear, BATCHman is here!” announced BATCHman.

The police chief looked up still recovering from the massive assault of sound and light. “Yes! Thank goodness you’re here! We are in dire need of your help!” he shouted above the imagined din.

BATCHman looked. “No need to yell, good citizen. We can h…”

The police chief gestured to all the loudspeakers in the office as well as the broken BATCHman blue box.

“Ahhhh, not again. Must remember, outside not inside.”

Quickly the Police chief guided him to the workstation “We’re locked out of Active Directory! Only one good account! Need to get in! GUI slow! Ears hurt, too!”

BATCHman thought for a moment. With Windows PowerShell, they could solve this easily. Nevertheless, they’d have to identify the locked-out accounts to make this quick.

Quickly, he entered the Windows PowerShell console and loaded up the ActiveDirectory module.

IMPORT-MODULE ActiveDirectory

Cmdlet looked over. “BATCHman, can we just pull up a user and have it show us whether they are locked out?”

Enjoying his sidekick’s enthusiasm BATCHman noted, “Yes, it is possible using the Properties parameter, but the ActiveDirectory module has a far more powerful feature called SEARCH-ADACCOUNT. To find all users locked out in Active Directory, we type this.”

SEARCH-ADACCOUNT –lockedout

“But, Cmdlet, if we need to make this go faster and unlock only the computers in a particular organizational unit or OU, we can specify parameters such as –searchbase.”

SEARCH-ADACCOUNT –searchbase ‘OU=Division31,OU=Locations,DC=Police,DC=Redmond,DC=Local’ –lockedout

Now, we can just quickly UNLOCK all the accounts by piping the results into UNLOCK-ADACCOUNT.

SEARCH-ADACCOUNT –searchbase ‘OU=Division31,OU=Locations,DC=Police,DC=Redmond,DC=Local’ –lockedout | UNLOCK-ADACCOUNT

Cmdlet blinked. One single line? “Holy Simple Simon, BATCHman! Windows PowerShell really is powerful!”

“Yes, it is. Now, quickly have the police chief verify that his staff and he can get in.”

The police chief logged in and verified all was well. “Thank you, BATCHman! You have saved the day! You’re our hero!”

BATCHman covered his ears from the shouting. “You’re quite welcome good citizen.”

Forgotten during all of this, Script Kitty looked up at BATCHman and purred, “Your outfit is purrrfectly delightful.”

BATCHman looked over. “Yes, maybe someday you’ll learn about the power of good and of Windows PowerShell. Crime not only doesn’t pay, it has a far worse budget for cool costumes.”

 

I want to thank Sean for another exciting episode of BATCHman. Join us tomorrow when The Scripting Wife learns about creating a profile for the Windows PowerShell console.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

 

 


The Scripting Wife Uses a Profile to Configure PowerShell

0
0

Summary: The Scripting Wife learns how to use a profile to configure the Windows PowerShell console.

 

Microsoft Scripting Guy Ed Wilson here. One of the coolest events of the year occurs in just a few days. Yes, that’s right, it’s Bouchercon in St. Louis. Bouchercon is a mystery writer’s conference, and the attendee list is a who’s-who among the cloak-and-dagger writer crowd. Conferees to Bouchercon also have the privilege of selecting the Anthony awards for the best mysteries.

It was a dark and stormy night in Charlotte, a town that knows how to keep its secrets, when a sudden disturbance in the other room cut through my concentration on my latest Windows PowerShell script like a dagger slicing through heavy drapery. As I moved stealthily through the foyer, across the living room, and into the kitchen, my eyes rapidly picked up the source of the cacophony of frustration-laden words that tumbled flat on the tile floor like yesterdays’ newspaper. I peeked around the corner.

Photo of Ed "Bouchercon" Wilson peeking around corner

“So, what’s ya beef, sweetheart?”

The Scripting Wife turned her gaze at me from her computer monitor and at that moment, I felt it. I felt it deep in the core of my being like a seven-inch stiletto plunged deep into my inner core, a spark of electricity that said she was the one. I looked down, and she was poking me in my stomach.

“I am not beefing. I have never beefed in my entire life. What is wrong with you anyway? What’s with the trench coat and the fedora?”

“A man on the job has to be prepared for all conditions, all emergencies, all kinds of stormy weather.”

“But we are inside. Besides, your Bogart voice is barely believable.”

“Don’t let the patter fool you, kid. Maybe I am not as tough as I am cracked up to be. Maybe that kind of a reputation is good for business. Inside, I might be a teddy bear, but don’t count on it. Besides, you knew it was Bogey.”

“Only because you always do Bogey. If you can get serious for a minute, I have a problem. Why do I always have to keep loading the PowerShell Community Extension Project every day?”

“Because you use it every day? That’s just a guess, but then my guesses are usually pretty good.”

“Of course, I use it every day, and that is why I need to load it.”

“Whadda I tell ya?”

“No. I mean, you never seem to load it, but I know you use the cmdlets. How is that possible?”

“Oh, I see what you mean. What you need to do is to create a profile. In your profile, you can load modules you find useful, and that you want to have immediately available,” I explained.

“Okay. So how do I get a profile,” she asked.

“Well the first thing to do, is to ensure that you do not already have a profile. Open your Windows PowerShell console, and use the Test-Path cmdlet to see if you have a profile. Use the $profile automatic variable to refer to your profile,” I instructed.

The Scripting Wife thought for a second, and typed the following command into the dark blue Windows PowerShell console:

Test-Path $PROFILE

As the Scripting Wife was typing, she took advantage of the Windows PowerShell tab expansion feature. Therefore, she did not have to type the complete command. What she actually typed was:

Test-p<tab><space>$p<tab><tab><enter>

In this case, <tab> represents the Tab key on the keyboard; <space> represents the spacebar; <enter> represents the Enter key on the keyboard.

On the Scripting Wife’s computer, Test-Path $profile returns False, which means that she does not have a profile. If your command returns True, you can open it in Notepad by using the following command:

Notepad $profile

To back up your profile, you can use this command (replace destination folder with a folder on your local computer):

Copy-item $profile destination folder

“Okay, I am assuming that I do not have a profile, because the Test-Path command came back and said False. So back to my original question: how do I get a profile?” she asked.

“It is simple. You use the New-Item cmdlet to tell it that you want to create an itemtype of file, and give it the $profile variable. Just to be on the safe side, go ahead and use the force switch.”

“You mean you are going to forgo your corny Star Wars ‘Use the force, Luke’ imitation?” she asked with a slightly disappointed voice.

“Yeah, you never seem to laugh at that one.”

“I never seem to laugh at any of them, but it never stopped you before,” she said.

The Scripting Wife said “New-Item $profile dash itemtype file dash force” to herself as she typed the following command:

New-Item $PROFILE -ItemType file –Force

The keys she actually typed are shown here:

New-i<tab><space>$pr<tab> <space>-i<tab><space>file<space>-f<tab><enter>

The reason the Scripting Wife used $pr<tab> was so that she did not have to tab past the $pid variable, which she had to do when she first used the Test-Path cmdlet. The commands and associated output are shown in the following figure.

Image of commands and associated output

“Obviously, it did something, but how is that going to automatically load the PowerShell Community Extensions for me?” she asked.

“Patience, grasshopper,” I said in my best Kung Fu voice.

“I think I prefer your Bogey to your Kung Fu voice. After all, I would rather be a babe than a grasshopper.”

“That reminds me of a Simon and Garfunkel song.”

“Oh, no!” she cried in mock horror. “Just get on with it.”

“Okay, now you have two choices: you can open your profile in Notepad, or you can open it in the Windows PowerShell ISE,” I explained.

“Let’s use Notepad. It is faster,” she said.

“All right. Type Notepad $profile,” I said.

The Scripting Wife did not hesitate as she typed the following command:

Notepad $profile

What she actually typed is shown here:

Notepad<space>$pr<tab><enter>

After she pressed Enter, a blank Notepad appeared, as shown in the following figure.

Image of blank Notepad

“Nothing happened,” she complained.

“Are you kidding? You opened Notepad, and not only that, look at the title bar. See how it points to the same location you saw earlier when you used the New-Item cmdlet to create your blank profile?”I asked.

“Okay,” she replied with a somewhat hesitant voice.

“Now, we will add the command to load the PSCX. After the command is added to your profile, it will happen each time you start the Windows PowerShell console. You ready?” I asked.

“You bet. Let’s do it.”

“Okay, in your open Notepad, add the Import-Module pscx command on the first line, and then save and close Notepad.”

She quickly typed the following command:

Import-Module pscx

“I wish that tab expansion worked inside Notepad,” she complained.

“What I do is type the command in the Windows PowerShell console first. Then when I know the command works, I highlight it and copy it, so I can paste it in Notepad. Now, close Windows PowerShell, and open it back up.”

“Ok. So how do I know that it worked?”

“Use the Get-Command cmdlet, and look for commands from the PSCX module,” I said.

The Scripting Wife used the GCM alias instead of typing Get-Command. Here is the command she typed:

gcm -Module pscx

The actual keystrokes she used are shown here:

gcm<space>-m<tab><enter>

The output from that command is shown in the following figure.

Image of output from command

“Wow, that is cool. Thanks,” she said.

“You’re welcome, sweetheart,” I replied in my Bogey voice.

She sprung from her chair and left the keyboard as if it were a thing on fire. Her perfume reminded the now-empty room that a vibrant being had once occupied the premises. The room seemed smaller now that she was gone.

 

The Scripting Wife will return tomorrow when she struggles to configure the Windows PowerShell ISE. I invite you to follow me on Twitter and Facebook. You can also follow The Scripting Wife on Twitter. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

 

 

The Scripting Wife Creates a PowerShell ISE Profile

0
0

Summary: The Scripting Wife learns how to create a Windows PowerShell ISE profile.

 

Note   This is part two in a series of articles in which The Scripting Wife learns how to work with Windows PowerShell profiles. In yesterday’s article, she created a profile for the Windows PowerShell console. That article also covers the basics of loading and checking commands. You should read that article before reading this one.

 

Microsoft Scripting Guy Ed Wilson here. It was the kind of stillness that can be heard. The early morning fog hugged the ground like a cloud that grew tired of floating. In my mind, I could hear the mournful strains of a saxophone as it intoned rich emotions with every note. A far-away diesel truck used its air brakes to arrest the runaway descent on a pernicious downgrade. As I sat on the lanai, the silence of the early morning stillness was nearly overwhelming.

I returned inside for another cup of English Breakfast tea, and I heard a rustling of papers as I entered the kitchen. I peeked around the corner.

Photo of Ed "Bouchercon" Wilson

There sitting at her computer is The Scripting Wife—and the sun is not even up yet!

“Good morning, Scripting Wife,” I said cheerily.

“What’s so good about it,” she replied.

“Well, for one thing you are awake to greet the day,” I said.

“The day will happen with or without a greeting from me,” she replied.

The Scripting Wife looked at me with a studied eye. She paused as if forming her words carefully.

“Just what are you made up for this morning?”

“Down these mean streets a man must walk who is himself not mean,” I said.

“You are not Philip Marlow, and you certainly are no Raymond Chandler,” she replied matter-of-factly.

“That’s right, but Bouchercon is only three days away, baby,” I said.

“You are not going to prance around here in a trench coat and fedora for three days! Besides, I am not certain that a Windows kind of guy should even be seen wearing a fedora,” she intoned.

“Those words hurt baby. They hurt me bad, but I know you did not mean them. So what’s up?”

“Well, yesterday you told me how to add a profile to Windows PowerShell, but when I open the Windows PowerShell ISE, I still have to manually load the PowerShell Community Extensions module. So I guess the profile is not working,” she replied.

“I know what your problem is, baby; but I cannot just out with it. You will need to discover it for yourself,” I said in my best Bogart imitation.

“So, are you going to help me?”

“Yeah, I will help you. Open the Windows PowerShell ISE and show me what you have tried.”

The Scripting Wife opened the Windows PowerShell ISE from inside the Start/All Programs/Accessories/Windows PowerShell folder. When the Windows PowerShell ISE was loaded, she typed the following command in the bottom pane (the command window):

Get-Command –module PSCX

The command and associated output are shown in the following figure.

Image of command and associated output

“Ok, so it looks as if you have not loaded the PSCX module. Another way to check this is to use the Get-Module cmdlet. The Get-Module cmdlet, with no parameters or switches, reports on the modules that are loaded. Try it.”

The Scripting Wife typed the following command in the bottom of the three panes that make up the Windows PowerShell ISE:

Get-Module

“Nothing happened,” she complained.

I looked over at her screen, and while no output from the command appeared, the command had run because it appeared in the output pane. Her screen output is shown in the following figure.

Image of screen output

“Ok, so you are not loading the PSCX module. Do you have a profile?”

“Well, duh, we created one yesterday,” she said caustically.

“We created a profile from the Windows PowerShell console, but we did not create one for the Windows PowerShell ISE. They are separate profiles, and they can contain different commands. For example, you might want to use something that would apply to the Windows PowerShell ISE, but not to the Windows PowerShell console. In my profile for the Windows PowerShell ISE, I create custom menus. Those commands would fail inside the Windows PowerShell console,” I said.

“That makes sense, I guess,” she said. “So how do I create a Windows PowerShell ISE profile?”

“You do it exactly the same way you did in the Windows PowerShell console. You even use the same $profile automatic variable.”

The Scripting Wife thought for a few seconds, and then she typed the following command. The first thing she did was use the Test-Path cmdlet to see if she already had a Windows PowerShell ISE profile:

Test-Path $profile

When she confirmed that the Windows PowerShell ISE profile did not exist, she used the New-Item cmdlet to create a new profile script. She used the $profile automatic variable to ensure the name of the file and the path would be correct. This command is shown here:

New-Item $profile -ItemType file –Force

The two commands and their associated output are shown in the following figure.

Image of commands and associated output

“You could open the newly created Windows PowerShell ISE profile in Notepad, just as you did yesterday, but because you already have the Windows PowerShell ISE open, why don’t you open it there,” I said.

“Ok, but how do I do that?”

“Well, you could use the File/Open dialogue box, but that box is rather inefficient. It wants you to manually navigate or search to find the file that is represented by the $profile variable. Unfortunately, it does not know what to do with a Windows PowerShell variable,” I lamented.

“That is not helpful, Script Monkey. I want to know what I can do, not what I cannot do,” she said with mock frustration (at least I think it was mock frustration).

“Ok, in the command pane, type ise space dollar profile.”

The Scripting Wife did not hesitate. Here is the command she typed:

ISE $Profile

The command and associated output are shown in the following figure.

Image of command and associated output

“At the top of the Windows PowerShell ISE, add the command to import the PSCX module, and save the file,” I said.

The Scripting Wife immediately typed the following command at the top of the profile file that is loaded in the Windows PowerShell ISE:

Import-Module PSCX

She then saved the file, and closed and reopened the Windows PowerShell ISE. After she had opened the ISE again, she used Get-Module to ensure the PSCX module had loaded. She also opened her $profile script back up in the ISE to inspect it. Here are the two commands she typed:

Import-Module PSCX

ISE $Profile

The command and associated output are shown in the following figure.

Image of command and associated output

“Cool,” she exclaimed, “way cooler, anyway, than that silly hat you are wearing.”

“I see.”

“Well, I am out of here. I am getting together with a couple of friends, and we are heading to the spa,” she said.

“I did not know that spa treatments were social activities.”

“Oh, they can be. Most certainly, they can be. See you later, gator.”

With that, she cleared the room. Outside, the fog had lifted. A beautiful day was in store.

 

I invite you to follow me on Twitter and Facebook. You can also follow The Scripting Wife on Twitter. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

 

 

Scripting Wife Adds a Cool Function to a PowerShell Profile

0
0

Summary: The Scripting Wife learns how to add a cool function to her Windows PowerShell profile.

 

The story you are about to read is true. We did not bother to change the names to protect the innocent. However, we did alter some of the facts.

 

The hot weather had finally broken, and fluffy white cotton ball clouds crowded the fall sky like Chicago workers queuing up to catch the “L.” I was working the day watch out of the Geek Division, when I received the squawk.

“One Microsoft one, one Microsoft one.”

“One Microsoft one, go ahead.”

“One Microsoft one, see the lady. She is having problems with her Windows PowerShell profile.”

“Roger.”

“No, it’s not Roger, it’s the Scripting Wife.”

“Roger, Scripting Wife.”

Dum dum dum…dum (music plays a la the Dragnet opening theme).

“I’m the Scripting Guy, and I carry a wireless keyboard.”

As seen in the figure below, I peeked around the corner slowly. One never knows when a user will turn hostile, and it is best not to take chances.

Photo of Ed "Bouchercon" Wilson

“There you are, my little script monkey,” squealed the Scripting Wife. “I have been looking for you. I have two things.”

“And?” I coaxed wearily.

“First, Happy Birthday! And guess what?”

“What?”

“I just signed us up for the panel discussion that’s going to be led by Mark Russinovich at Bouchercon in St. Louis.”

“Cool.”

“Just one thing—you need to leave that ratty old Mackintosh here. The Microsoft Scripting Guy should not be parading around in anything called “Mackintosh” anyway!”

“I see what you did there. And what is the second thing?”

“I am wondering about editing my profile, but I cannot remember how we did it yesterday.”

Note   This is part three of a four-part series about the Scripting Wife and the profile. On Monday, she created a profile for the Windows PowerShell console. Yesterday, she created a profile for the Windows PowerShell ISE.

“Well, sweetheart, the easiest way to do that is to create a function and add it to your profile. So here’s looking at you kid,” I said in my best Humphrey Bogart voice.

“Can it Script Monkey. Now get to work. Cut the comedy, and show me what you are talking about. I have work to do, and you are not helping.”

“Ok, first we will add a function to the profile you created for the Windows PowerShell console. Next, we will add a function to the one you created for the Windows PowerShell ISE. So open the Windows PowerShell console, and type notepad $profile,” I instructed.

The Scripting Wife wasted no time in clicking the Windows PowerShell icon she had created on her Quick Launch toolbar, and as soon as the Windows PowerShell console was running, she typed the following command:

Notepad $profile

Because she used tab expansion, the Scripting Wife did not have to completely type the $profile variable name. The keystrokes seen here are exactly what she typed (<space> is the Spacebar, <tab> is the Tab key, and <enter> is the Enter key).

Notepad<space>$pr<tab><enter>

The command and associated output are shown in the following figure.

“Now, there are usually five things that I put in a Windows PowerShell profile. I like to separate the areas with comments. The five things are variable, function, psdrive, alias, and command. So add a comment on new lines in your profile for each of those five things,” I said.

The Scripting Wife thought for about a minute. She looked up, and began to say something. I thought I saw her beginning to mouth the word, “Huh,” but it might have been my imagination. At last, she turned to the Windows PowerShell profile that was open in Notepad, and went to the first line that contained the Import-Module pscx command. She went to the beginning of the line, and pressed Enter. Then she up-arrowed back to the first line. Now she was ready to add the comments. Here is what she typed:

# Variable

# function

# psdrive

# alias

# command

The following figure illustrates her current Windows PowerShell profile.

Image of current profile of Scripting Wife

“Now, close Notepad, close Windows PowerShell, start Windows PowerShell again, and once again open the Windows PowerShell profile in Notepad,” I said.

Here are the steps the Scripting Wife followed:

  1. Saved the Windows PowerShell profile in Notepad by clicking File and then Save from the Notepad menu.
  2. Closed Notepad.
  3. Closed Windows PowerShell.
  4. Started Windows PowerShell again.
  5. Looked for any errors.
  6. Tested to ensure the PSCX module still loaded by using the Get-Module cmdlet.

“Okay, now what?” the Scripting Wife asked.

“Now that we have verified that we have not messed up the profile with adding those comments, it is time to create a custom function to edit your profile. The first thing to do is to come up with a name. The name should follow the two-part naming convention,” I instructed.

“You mean like, CanIt-ScriptMonkey?” she asked.

“Yes, it is a two-part name, but the problem is that CanIt is not an approved verb,” I said.

“And what are you, the verb police?”

“No, I am not the verb police. I am the Scripting Guy, and I carry a wireless keyboard,” I said in my best Sgt. Joe Friday voice. “But if your function ever wants to grow up and live in a module, the Import-Module cmdlet does have a verb police.”

“Okay, then why don’t I call my new function Edit-Profile?” she asked.

“Well, that would technically work. Edit is an approved verb, but it is used as a data verb. You can see this by using the Get-Verb cmdlet,” I said while pointing to the results of the Get-Verb command seen in the following figure.

Image of results of Get-Verb cmdlet

“Why don’t you use the verb Set? It is used with Set-Content, a standard cmdlet that is used to write data to a file. This is essentially what you are doing: writing data to a file,” I suggested.

“Okay. So how do I do it?”

“Go to the # function portion of your profile and use the function keyword to tell Windows PowerShell you are getting ready to create a new function. Next, provide it with the name you are going to use: Set-Profile. After you have done that, let me know.”

The Scripting Wife thought for a few seconds, and then typed Notepad $Profile into the open Windows PowerShell console. Next, she located the # function portion, and then she typed the command, Function Set-Profile, in Notepad. The exact commands she typed are shown here:

Notepad<space>$pr<tab><enter>

When Notepad appeared, she typed the following in the profile file:

Function Set-Profile

The profile now appeared as shown in the following figure.

Image of updated profile

The Scripting Wife looked up as if to ask, “Am I doing it right?” But she did not ask. She did not have to seek a cheap reassurance such as that. I continued with my instruction.

“Now on the line under your new Function Set-Profile line, I need you to open a curly bracket., Two lines below that, I need you to close the curly brackets. After you have done this, let me know.”

This time, it did not take the Scripting Wife any time at all to make the two keystrokes. When she was finished, her code now appeared as it is shown here:

Function Set-Profile

{

 

}

“Very good. Now, inside the opening and the closing curly brackets, add the command you used to open your Windows PowerShell profile in Notepad,” I said.

A few clickety clickety clacks later, and the Scripting Wife had completed her first function. The code for her new function is shown here:

Function Set-Profile

{

 notepad $profile

}

I told her to add a comment after the closing curly bracket so that she could easily see where the function ended. She did not like it, but she did it anyway, with nothing more than a simple, “Can it, Script Monkey,” for my effort. The Scripting Wife’s newly edited Windows PowerShell console profile appears in the following figure.

Image of newly edited Windows PowerShell console profile

The Scripting Wife looked up, waved her hand, and said, “You can go. I need to figure out what other panel discussions I want to attend at Bouchercon. You would be wise to do the same.”

And with that, I was dismissed. Join me tomorrow when the Scripting Wife returns once again, and she continues to monkey around with her Windows PowerShell profile.

 

I invite you to follow me on Twitter and Facebook. You can also follow the Scripting Wife on Twitter. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

 

Scripting Wife Uses PowerShell to Update Sysinternals Tools

0
0

Summary: The Scripting Wife adds a function to her Windows PowerShell profile to update the Sysinternals tools on her computer.

 

Microsoft Scripting Guy Ed Wilson here. I had completed my IT Time radio interview with Blain Barton for my series on Windows PowerShell best practices, when I heard the commotion from downstairs. I quickly donned my trench coat and hat, and eased into the hallway. The following photo is of me on the prowl.

Photo of Ed "Bouchercon" Wilson

I eased into the kitchen, and spotted the Scripting Wife at her keyboard. She looked up at me, and stared.

“You look like Knute Rockne in that outfit,” she said, “I need help with my profile.”

“A profile? Write one for the Gipper,” I said.

“Anyway, the panel discussion with Mark Russinvoch is tomorrow afternoon at Bouchercon. I was curious, about getting the Sysinternals tools installed on my computer. But I am also curious about keeping them up to date, because I know he updates them quite regularly,” she said.

“So you want to install the Sysinternals tools on your computer?”

“Yes.”

“And you would like to have an easy way to update the tools from time to time?”

“Yes. You know Mark is cool. He signed my copy of Zero Day for me at Tech∙Ed,” she said as she showed me the following photo from her computer (thanks to Ron Taylor from Ottawa for taking this photo and sharing it with me).

Photo of the Scripting Wife with Mark Russinovich

“Yes, I know. How come you don’t keep pictures of me signing my Windows PowerShell 2.0 Best Practices book for you,” I asked.

“Well, for one thing, I don’t have any pictures of you signing my copy of your book. For a second thing, I don’t need your autograph on the book—I am in the dedication,” she said matter-of-factly.

“Okay. Makes sense. About your problem of downloading, and installing the Sysinternals tools, I have found a really cool script called Get-Sysinternals on the Scripting Guy’s Script Repository. Unfortunately, the copy code button does not work for this script, but I was able to highlight the text field, and paste it into the Windows PowerShell ISE. I then ran it, and it created a directory off the Windows Directory, and copied all the files there. It also edited your path statement so that you can easily use the tools,” I said.

“Okay. Show me the script, and its output,” she said.

I turned the monitor so that she could see the Windows PowerShell ISE and the associated output. It is shown in the following figure.

Image of Windows PowerShell ISE and associated output

“That is pretty cool. But how could I put that in my profile? I don’t want that great big monster script in my profile.”

“Well, the first thing to do is to save the script to your Windows PowerShell profile directory. You could then dot-source it into your profile, but the script does not play well with others. So we will take a different approach. First open your Windows PowerShell console profile in Notepad by using the Set-Profile function you added yesterday.”

Note   This is part four of a four-part series on the Scripting Wife and the Windows PowerShell profile. On Monday, she created a profile for the Windows PowerShell console. On Tuesday, she created a profile for the Windows PowerShell ISE. On Wednesday, she formatted the profile file and added a Set-Profile function to her Windows PowerShell console profile.

“Okay, now what?” she asked. Her Windows PowerShell console profile is shown in the following figure.

Image of the Scripting Wife's console profile

“Copy the entire contents of your Windows PowerShell console to your Windows PowerShell ISE profile. First, copy the Windows PowerShell console profile to the clipboard.”

The Scripting Wife clicked Notepad to ensure it was active. Then she pressed CTRL+A to select all contents of the Windows PowerShell profile in Notepad. Then she pressed CTRL+C to copy the profile to Clipboard. She pressed CTRL+A, and then she pressed CTRL+C to copy it to Clipboard.”

After the Scripting Wife had copied the contents of her Windows PowerShell console profile to her Windows PowerShell ISE profile, it was time to add a variable and a function.

“Why do I need to add a variable?” asked the Scripting Wife.

“Because it will make things a bit easier. You want to be able to access your script without having to do a lot of extra work. There is already the $profile variable that points to the Windows PowerShell profiles in your Windows PowerShell directory in your normal user profile. I want you to create a variable that points only to the Windows PowerShell directory inside your user profile.”

“I see,” she said.

“In the # Variable section of profile, create a new variable named $myPsHome, and set it equal to the parent portion of the $profile variable. The parent portion of the $profile variable refers to the directory in which the Windows PowerShell profile file is located. To split the path that is contained in the $profile variable, you will want to use the Split-Path cmdlet,” I instructed.

I could see the word huh forming on her brow for just a few seconds. Then I could see by the word eureka gradually replacing the word huh. I bet the Scripting Wife did not realize her forehead contained an LED display. She lowered her head and began to type. Slowly, surely, and with confidence, her keystrokes gathered speed. The command she typed is shown here:

$myPsHome = Split-Path -path $profile –parent

The exact keystrokes she typed are shown here:

$myPsHome<space>=<space>Split-p<tab><space>-p<tab><space>$pro<tab><space>-p<tab><tab>

“Very good. Now, what you want to do is to create a custom function to launch your Get-Sysinternals.ps1 script,” I said.

“Why do I have to do that?” she asked.

“Well, you don’t. But because of the way the script is written, you cannot dot-source it into your Windows PowerShell profile. It will run the entire script every time you open Windows PowerShell. If the script had a main function you could call when you wanted to run the script, you could just dot-source it,” I explained.

“I see,” she said in a tentative voice.

“You could simply type the full path to the script every time you wanted to run the script, but that could be a pain because the script requires administrator rights. Therefore, when you open Windows PowerShell with administrator rights, it drops you into the Windows\System32 directory. I really do not want you messing around in that directory,” I said.

“That’s good. I don’t want to hose my computer,” she said.

“Hose?” I asked.

“Yes, it is a computer term. It stands for ‘hardware or software error,’” she said.

I began to wonder with whom she had been chatting during the PowerScripting Podcast.

“Okay, now that you have the variable for $myPsHome, create a function. You can call the function Get-SysInternals. Inside the function, you will use the Invoke-Expression cmdlet to invoke the Get-SysInternals.ps1 script from within your Windows PowerShell folder from within your user profile,” I said.

She thought about it for a minute, and finally she typed the function. Here is the function she created.

Function get-Sysinternals

{

 invoke-expression "$myPsHOME\get-sysinternals.ps1"

} #end get-sysinternals

The Scripting Wife’s revised Windows PowerShell ISE profile is shown in the following figure.

Image of the Scripting Wife's revised Windows PowerShell ISE profile

“Now, close your Windows PowerShell ISE, and open it again but with administrator rights. To do this, hold down Shift, and right-click the Windows PowerShell ISE icon. Next, click “Run as Administrator” in the shortcut menu. In the command pane, type Get-SysInternals and press Enter. This will run your custom function and call the script to update any Sysinternals tools that have changed since the last time you ran the script,” I said.

“Okay. This is easy now,” she said.

The Scripting Wife opened the Window PowerShell ISE, and ran the Get-Sysinternals function. The command and associated output are shown in the following figure.

Image of command and associated output

“Now that I have gotten the Sysinternals commands installed and updated on my computer, I am out of here,” the Scripting Wife said.

“But what about…oh, never mind,” I said.

“Tata for now,” she said. And with that, she was gone.

 

Join me tomorrow for Episode 10 of the BATCHman series.

I invite you to follow me on Twitter and Facebook. You can also follow the Scripting Wife on Twitter If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

 

 

Use PowerShell and Regular Expressions to Parse Handle Output

0
0

Summary: Windows PowerShell superhero BATCHman uses regular expressions to parse output from handle.

 

Microsoft Scripting Guy Ed Wilson here. Today we have Episode 10 of the BATCHman series.

 BATCHman and Cmdlet logo

Whenever trouble happens in systems and people will call,
and darkness rolls out causing your fall,
Creatures of bits roam in the night,
Shine to the sky, the bright bluish light,

and call to…BATCHman !

…and, oh yes, his sidekick Boy Blunder Cmdlet, too.

 

A smell rolls out from the darkness. An evil smell.

“Don’t look at me!” Cmdlet looks defensively “I didn’t do it!”

The BATCHman looks intensely at his “BATCH-o-Meter for Evil Detecting.” “No, little buddy, it’s the smell of evil afoot. Somewhere in this city, a crime against infrastructure is occurring. I can feel it, I can smell it…” 

 

***Meanwhile, in a far smellier section of the city, evil is afoot at the Redmond Pocket Protector Recycling Plant.*** 

“Our backup has failed again! Why??!”

Jane the local IT pro/accountant/phone guru/everything else stares at the logs. “More than 3,000 files not backed up again! All Word and Excel documents! Why?!!”

In the distance, somewhere within the shadows, a mad cackle can be heard. The sound of a shrieking creature, perhaps a Banshee or just a squirrel that listened to a bit too much disco music. But a horrid sound echoed throughout the building.

“Your files are all MINE! MIIIIIIINNNNNEEEE!!! Your backup will never work again! Hee-hee-hee-hee!” the sound echoed ominously.

Out of the corner of her eye, Jane spotted a shadow slither into the darkness. Immediately, she knew what to do. Grabbing her smart phone and popping open Twitter, she pinged the one person that could help her in this dire hour. 

 

***Meanwhile, in a far less smelly section of the city, evil is not afoot.*** 

Sounds of a budgie echoed throughout the BATCHcave.

“Holy shrieking parakeets, BATCHman! It’s the BATCHtweet account!”

Quickly popping open a module in the BATCHbelt, BATCHman checked for his updates.

“No, I don’t want a million dollars. No, I don’t want a free crate of Tang. Cmdlet! I was right! There was evil afoot and I’m not talking about what you had for lunch! Look.”

@JaneITGuru @Batchman! Quick! Help! Backups failing daily! Too many open files! Shrieking! Help me BATCHman!

“Looks like that new Twitter account paid off, BATCHman. Glad I suggested it!”

“Yes Cmdlet! Quickly! To the BATCHcycles!”

Cmdlet stared at the blue tricycle with “Cmdlet“ written on the side in permanent marker. “Must we?”

“We’re a green organization here!” cried BATCHman as he mounted his 40-speed carbon fiber, midnight blue special “Quickly! Crime waits for no-one!” 

 

***Moments later, Cmdlet is huffing and puffing.*** 

“Huff…puff…no more…*gasp*…Double Downs for…*ack*…breakfast!” gasped Cmdlet between breaths.

Jane looked out to greet BATCHman and the heavily sweating Cmdlet at the door. “Oh, thank goodness you’re here! None of our backups are working on the file server! It’s failing because there are documents open when they shouldn’t be! Plus there’s this noise.”

BATCHman steps off, listening keenly to the air. The shrieking cackling sound could be heard ominously throughout the building.

“I’d know that sound anywhere.” BATCHman shook his head. “That’s the Tapeworm! I remember this criminal from an article in BadGuys Weekly.”

“The Tapeworm?” Jane queried.

“Yes. He was once a brilliant IT professional, but his mind went and snapped one day. He was manning the backups and spent twenty hours restoring an email database from QIC-20 tapes, only to find it was because somebody wanted a cat picture. Since that day, Tapeworm attaches himself to file systems and ruins backups.”

“Holy, Hello Kitty!” burst out Cmdlet “I had no idea cats were so evil!”

“Yes, so what is happening here. I heard ‘failed backups.’”

Jane gestured to the backup logs indicating failures due to open files.

“We’ve even tried selecting the open files in Computer Management, but it takes far too long to enumerate! Plus massive piles of different documents are reopened daily before the backup.”

“BATCHman!” burst out Cmdlet “We’ve got to help her get a handle on this!”

“Yes,” the Tilley-hatted one muttered. “Funny you should mention ‘Handle’. That’s the perfect answer.”

Poor Cmdlet stared at the floor confused. Deciding to practice telekinesis on his shoelaces was more productive. “I don’t get it,” was all he muttered.

“Handle as in Handle.exe from Sysinternals. We could use that to close the files!”

Cmdlet groaned in dismay as yet another horrible joke left BATCHman’s lips. “Holy PUNishment, BATCHman—that was horrible!”

Our hero smiled with a sly grin. Another well-played play on words.

Jane looked up. “But BATCHman. I already thought of that. We need something that can be automated. That application can’t be automated. Normally you run it, it shows the open file Handles in HEX with the process numbers, and then you manually run it again like this to close a file handle.”

HANDLE.EXE –c 2a3 –p 5342

Our hero stood up proudly. “For ordinary people and mere mortals, no. But for us, the kings of automation, we have…” he paused ever so dramatically while pulling out a megaphone “WINDOWS POWERSHELL!”

While rubbing their ears, they looked at BATCHman equally puzzled. “Automate it how?”

BATCHman looked over. “Remember the first rule of Windows PowerShell, which is…”

“Ooooh! Ooooooooo!” Cmdlet jumped up and down like a gerbil on a hot coal “I know! Everything is an object!”

“Exactly! If I ran Handle while in Windows PowerShell and got some output like this…”

Image of output when running Handle in Windows PowerShell

”...we’d notice there is a consistent pattern of well-formatted columns. So what we could do is store the output in a Windows PowerShell variable to play with it like this.”

$ScreenOutput=.\HANDLE.EXE DOCX

Cmdlet stared at the screen with Jane then burst out. “HOLY PATTERN BUFFER BATCHman! Every line has ‘PID:’ before the Process ID and the word ‘File’ with a pile of blank spaces before the File Handle! If we could somehow pull out the numbers after PID and FILE we’d be halfway there. But we need to clean all the extra stuff out too, like the title.”

BATCHman looked at his sidekick. “So what do you think we could do to simplify this output?”

Cmdlet rubbed his hands eagerly at the thought of solving the puzzle. “I’ll wager we could run this output through Select-String to pull only the lines that have the pid: field in it!”

$ScreenOutput | SELECT-STRING –pattern ‘pid: ’

Cmdlet began to dance a jig like a leprechaun who’d gotten away with his box of Lucky Charms. “W0000000t! Aha!”

“That’s good but we can go one step better. With the \w from regular expressions, we can tell the string to find us all letters up to but not counting spaces. We’ll add an asterisk, which means all characters following that match this pattern. We can store away the results in a variable to make it easier to work and manipulate.”

$ProcessIDResults=$ScreenOutput | SELECT-STRING –pattern ‘pid: [\w]*’

Cmdlet thought. “So we could run a similar search for lines beginning with File, but how do we specify to find all data after that up until the colon character that follows the file Handle?

BATCHman explained. “In regular expressions, you can also specify the pattern of \s\S, which means accept any character including spaces. Doing this we can pull down only the data we need. We can tell it to search for all data beginning with File and ending with a colon, like this.”

$FileHandleResults=$ScreenOutput | SELECT-STRING –pattern ‘File [s\S]*?:’

Cmdlet looked. “So regular expressions can be used in many situations, BATCHman, but how does this help us? We need to get this information back to the Handle program!”

“Never fear, little chum. Let’s see which methods and properties we have available with a Get-Member.”

$ProcessIDResults | GET-MEMBER

“As you can see, like when we battled Dr. Regex, there is a Matches property. Let’s take a look at the data in one of those."

$ProcessIDResults[0].matches[0]

“And of course, if we run Get-Member against this, we can see which methods and properties are available on this object.”

$ProcessIDResults[0].matches[0] | GET-MEMBER

Cmdlet’s eyes lit up when he saw tostring() as a method. He knew from his previous experiences with string objects in Windows PowerShell there was a substring() method available.

“BATCHman! We could convert each match to a string! And because we know the data is from the Matches object, we could run a substring() on the output!” Cmdlet barked out like a chihuahua.

Before BATCHman could reply, a loud blaring klaxon went off. Flashing neon lights lit the city streets!

“Oh, no!” burst out BATCHman. “That’s the alarm on the WinMobile! Somebody’s gotten to it!” as he barreled down the stairs.

Will BATCHman find the WinMobile intact?
Will Cmdlet finalize the solution for Handle?
Will Tapeworm ever get a speaking part?

Find out at the same BATCHtime, same BATCHchannel in the next episode of BATCHman and Cmdlet!

 

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

 

 

Viewing all 3333 articles
Browse latest View live




Latest Images