September 2012 Archives

Ran into a simple one today to share.  Wish I grabbed the screen shot today.

I noted my new install of SCVMM 2012 wouldn’t finish on my copy of Server 2008R2 Enterprise.   It complained about being unable to launch Powershell and Failover clustering in the final window.

The answer? Duh! Make sure the Failover Clustering RSAT is installed on the SCVMM Server.  I just went ahead and cheated and threw them all on.

Import-Module ServerManager; GET-WindowsFeature *RSAT* | Add-WindowsFeature; RESTART-COMPUTER

I reran the Install and I have SCVMM2012 running happily now. Smile

Ok.  One last bit of madness.  

I would play with an Exchange 5.5 scenario but the funny thing is, I don’t think I have the Media anywhere…. Maybe if I ask Kevin nicely.

The whole point of this task wasn’t to really so much Manage an NT4 server but to determine what data I COULD pull from a legacy Domain that was so far out of support, you’d be stuck.  I wanted to see what Powershell could REALLY do.  I’ve been impressed.

My final task I decided was to try and pull out Group memberships from archaic and stale domain.   Completely migrate whatever we could onto a new platform.

Having the Groups created in Active Directory from the old NT4 domain just saves me typing.   It’s NICE but it’s not the whole beast.   Getting the user membership migrated over, THAT’S the big time saver.

So in our CONTOSO domain we obtained the groups by Binding to the Domain with the [ADSI] provider and then running a quick Cmdlet to filter out only Groups.

$NTDomain=[ADSI]”WinNT://CONTOSO”

$Groups=$NTDomain.psbase.children | where { $_.SchemaClassName –eq “group” }

But the bigger challenge would be to pull  out the memberships and store them into something useful (Like say a CSV file?  With the GroupName in a column?)

I found that if I ran a direct bind to a group like this

$groupname=[ADSI]”WinNT://CONTOSO/Administrators”

$groupname.members()

I could pull out Something.  But the something was a result like below

image

But thanks to a posting from Brandon Shell (@bsonposh) I found, “Enumerating Local Group Membership” this wasn’t so bad.  

Well, I fibbed.  It LOOKED bad because it involved a funky method that made my head hurt, but his solution worked perfectly.   You had to pipe each member of the returned array into THIS to get the Name of the User.

$_.gettype().invokemember("Name",'GetProperty',$null,$_,$null)

Now I know why I hated working with NT4!

So running our initial list of Group Members through Brandon’s special Powershell decoder ring….

$Groupname.members() | foreach { $_.gettype().invokemember("Name",'GetProperty',$null,$_,$null)}

and we now have USEFUL information.

image

Now to pull out this pile and produce something useful CSV output

We also have the list of Groups from Before.   Within the property returned is “PATH” which is the Path we need to bind to with [ADSI].   We’ll use that to individually bind to the Groups, pull their membership and output all to a CSV file we’ll build.

# Bind to the NT4 Domain Contoso

$NTDomain=[ADSI]”WinNT://CONTOSO”

$Groups=$NTDomain.psbase.children | where { $_.SchemaClassName –eq “group” }

# Define my Quotes and commas

# Honestly?  It’s to avoid my blog software switching the characters on me

# I could just as well use this ‘”Groupname”,”Groupmember”’

# But every so often the characters switch.

# Besides, this is more readable Smile

$quote=[char][byte]34

$comma=[char][byte]44

# Create a blank file to hold the data

NEW-ITEM C:\Powershell\Groupmembers.csv –itemtype file –force

# Add the Header to our CSV file

add-content –value ($Quote+”GroupName”+$quote+$comma+$Quote+”Groupmember”+$quote) –path c:\powershell\groupmembers.csv

# Step through the Groups

$groups | foreach {

# Store away the Group name

$name=$_.Name;

# Step through the membership

$_.members() | foreach {

# Run this through Brandon Shell’s (@bsonposh) secret Decoder ring…

$member=$_.gettype().invokemember("Name",'GetProperty',$null,$_,$null)

# Store away the data and place it into a CSV file

$Data=$quote+$Name+$quote+$comma+$quote+$Member+$quote

add-content –value $data –path C:\Powershell\Groupmembers.csv

}

}

At the end you should have a CSV file that looks like this

image

Which if you copy over to a USB key (And presuming you already created the Group names in the Server 2012 BEFORE with the previous data gathering session) you could do something like this to populate the groups.

IMPORT-CSV C:\Powershell\GroupMembers.csv | Foreach { ADD-ADGROUPMEMBER $_.Groupname $_.Groupmember }

Oh look.  All my memberships populated in a NEW Domain Smile Sweeeeet.

Feelin’ that Power flowing free with PowerShell

Sean
The Energized Tech

Now listen clearly.  This is NOT a hack.  It’s meant to do this. 

I can also hear a few people (ok, MORE than a few, a LOT) screaming “WHY?! WHY?!? WHYYYY????!??!!!!”

Just cuz.  I was curious if it could work and to what degree.

So here we have a lovely little Domain on an NT4 server called “CONTOSO”, leftover from my previous session of pulling users out. 

I wanted to see just what it would take.

Process is simple actually.

Bind to the Domain

Create a user object

Populate the necessary fields

Set it in stone

Now if there are any small children watching this?  BACK AWAY!  I am working with a VERY old and INSECURE system that might just Blue Screen and eat something.

Bind to the Domain while logged as an account with Domain Admin rights

$NTdomain=[ADSI]”WinNT://CONTOSO”

Create the User Object

$NEWUser=$NTDomain.psbase.Children.add(“John Smith”,”user”)

Populate the necessary fields

$NEWUser.setPassword(“ReallyStupidPasswordSinceThisIsNT4”)

$NewUser.Put(“Description”,”Our Standard Generic User”)

Set it in stone

$Newuser.Setinfo()

Yes.  It works.  It follows the exact same principals and rules when creating and modifying local machine accounts and groups in Windows 7.

I’m not quite sure where this is actually USEFUL but it was fun messing about Smile

The Power of Shell took me over!

Sean
The Energized Tech

Now before I go anywhere with this I have to take off my Tilley and bow to my co-worker Kevin McKeown.   I looked over at him the other day and said “Hey, any chance you have NT4 server anywhere in the archives?”

Kevin ran off into his private dungeon somewhere in Northern Canada, dug through piles of Commodore cables, various bits and pieces of SCSI1 drives and a small toad (don’t ask) and bounced into the office Monday.

“You mean these?” He laid out before be not ONLY the original NT4 Server media, the Option Pack but EVEN NT4 workstation.”

“I’m pretty certain these disks won’t work.  They’ve been buried in the basement for YEARS.”

I shrugged and started down the path to my Doom on my Windows 7 workstation, only armed with Windows Virtual PC, a pre-installed Windows XP Mode, some ancient media and a cross of the fingers.

The first part was installing NT4 into Windows Virtual PC.  Very interesting that it DID pick up the Native Network card and Windows Virtual PC provided a Video card NT4 liked.   I actually had COLORS and NETWORKING.

Spinning up the old Wizard, I choose to enable it as a Primary Domain Controller for the CONTOSO domain with a Static IP Address of 192.168.45.10

Then it was time to get workstation on this puppy that could use Powershell.  I initially tried Windows 7, it looked up at me and said “NT4, are you KIDDING?!” so I dropped to a machine I knew WOULD work with NT4 in the past, Windows XP, which could also use a currently supported version of Powershell.

We start off with an ordinary Windows XP workstation.  Nothing up this sleeve, nothing up here (tapping head) and

Join Windows XP to NT 4 Domain

We follow the following two articles first BEFORE joining Windows XP to the NT4 domain

Ensure NetBIOS over TCP/IP is Enabled under the WINS tab in TCP/IP and pointing to the NT 4.0 WINS Server

As per Knowledge Base: 318266 - A Windows XP Client Cannot Log On to a Windows NT 4.0 Domain Disable the option in the Windows XP workstation for “Domain Member:Digitally encrypt or sign secure channel data (always)” to Disabled

…and then join a computer to the Domain in whatever manner you deem normal (Yes, even if that means you’re juggling Eggs and singing the latest pop hits while wearing a beanie)

image

Now that you’ve dropped your Security pants, you can manage this sucker

Install .NET Framework 2.0 SP1 and Windows Management Framework 2.0 (Powershell 2.0) on that computer to make this all happen.  Without this, I wouldn’t be able to use the word “Powershell” in the title of the article.

Now the first trick is to Bind to the CONTOS Domain with Windows Powershell.  We’re going to be using the older WinNT provider here (Yes, Powershell was designed to talk to an NT4 Domain, how cool is that?)

$NTDomain=[ADSI]”WinNT://CONTOS”

Once you have bound yourself to the Albatross (er… security hol…. NT4 Domain!) you can at least start doing some queries.  

PHASE 1 – COLLECT UNDERPANTS!

No, wait.  Obtain DATA from old Domain CONTOSO

Get your list of User accounts

$userlist=$NTDomain.psbase.children |  Where { $_.SchemaClassName –eq “user” } | Select-object Description,Name,Fullname,HomeDirDrive,HomeDirectory,LoginScript,objectSID,PrimaryGroupID,UserFlags

image

Get a list of your Domain Groups

$grouplist=$NTDomain.psbase.children |  Where { $_.SchemaClassName –eq “group” } | Select-object Description,Name,GroupType,objectSID

And perhaps your computers?

$computerlist=$NTDomain.psbase.children |  Where { $_.SchemaClassName –eq “computer” } | Select-object Division,Name,OperatingSystem,OperatingSystemVersion,Owner,Processor,ProcessorCount

Now suddenly with this information in our hands, doesn’t it all seem possible?  We can store away the data as CSV files for our new Server 2012 domain in the following manner.

$userlist | export-csv c:\powershell\userlist.csv

$grouplist | export-csv c:\powershell\grouplist.csv

$computerlist | export-csv c:\powershell\computerlist.csv

Now that the data you want is in something clean like a CSV file, you can bring that over to your DC on the new Windows Server 2012 domain, or nearest handy workstation enabled with RSAT and the Active Directory Module.

PHASE 2 – ??? –

Oh right, Import Accounts, Computers and Groups into NEW Domain Fabrikam.local

Once you are on the new machine you can use the following script to rebuild the Groups in Active Directory

$grouplist Import-CSV C:\Powershell\Grouplist.csv

[array]$groups="Global"
[array]$groups+="DomainLocal"

$grouplist | foreach { new-adgroup –GroupScope ($groups[(([int]$_.GroupType)/2)-1] ) –DisplayName $_.Name –Name $_.Name –Description $_.Description }

Smiling now?  A LITTLE BIT LESS TYPING?

It gets better.   Now we can pre-populate all of your computers in Active Directory.

$computerlist Import-CSV C:\Powershell\Computerlist.csv

$computerlist | foreach { new-adcomputer –Name $_.Name –DisplayName $_.Name –description $_.Division }

Now importing staff is a little different.  We’re playing a very basic scenario in which we don’t have Exchange 5.5 (although if you are creative, Powershell I believe can query IT via LDAP) but we’ll have a simple scenario with the following details.  One of things we WILL have to do since Windows NT has a VERY basic UserID setup is Split the FullName into some userful details before creating it.

$userlist=import-csv C:\poweshell\userlist.csv

$UPN='@fabrikam.local'
$Path='OU=Users,OU=Offices,DC=Fabrikam,DC=local’
$DOMAIN='FABRIKAM'

$userlist | foreach {

$Password=(CONVERTTO-SecureString ‘BadPassword1’ –asplaintext –force)

$LoginID=$_.Name+$UPN

$GivenName=($_.Displayname.split(“ “))[0]

$Surname=($_.Displayname.split(“ “))[1]

NEW-ADUSER –path $Path -name $_.Displayname -displayname $_.DisplayName -description $_.Description –accountpassword $Password -changepasswordatlogon $TRUE -enabled $TRUE -givenname $Givenname -homedirectory $_.HomeDirectory -homedrive $_.HomeDirDrive -userprincipalname $LoginID -samaccountname $_.Name -scriptpath $LoginScript -surname $Surname

}

PHASE 3 – PROFIT! (Yes sit back and let the computer do the work!)

The Scripts make take some time to populate your Active Directory depending on the size of your old Domain but imagine how you could just sit back and bill for what every else says “Whoa! dude! Migrate NT4 to Windows Server 2012? Not gonna happen”

Well we might not get a direct migration, but we can sure get our data out of the old Domain

Stick around, I’m going to try and create a user in this beast and see if I can pull some Group Memberships.

Remember, it’s all thanks to the POWER of Powershell!

Sean
The Energized Tech

Go online and check the sample scripts for Setting a BIOS setting like Wake on LAN from Dell.   You’ll probably twist your head and go “YEeeeeeaaaachhhh!”

But that’s not Dell’s fault.  WMI works but it’s not fun when working with Methods.  I wish I could remember the phrase James O’Neill said about working with WMI.  It Sums it up PERFECTLY.

But that doesn’t mean you can’t make it easy.  That’s where Powershell comes in.

So here’s the sample from Dell to Enable Wake on LAN in the BIOS

(Get-WmiObject DCIM_BIOSService -namespace root\dcim\sysman).SetBIOSAttributes($null,$null,"Wake-On-LAN","4")

Now if you asked me to remember that, I’d find a large copy of the Windows NT3.51 Resource Kit and wallop you in the arm with it.  No.  No. and “Nooooooooo!!!!!!”

But I CAN make this more useful.   I can turn this into a simple script to just take the name and new setting as parameters along with the computer name.

Param(

     [string]$AttributeName,

     [string]$Value
)

(Get-WmiObject DCIM_BIOSService -namespace root\dcim\sysman -ComputerName $computername).SetBIOSAttributes($null,$null,$AttributeName,$Value)

Now save this as a script called SET-DELLBIOS.PS1

Now you can just do this

SET-DELLBIOS.PS1 –computername mycomputername –AttributeName ‘Wake-On-Lan’ –Value ‘4’

Unless you absolutely live and breathe nothing but WMI, you may find this an easier way to set your Dell BIOS settings via Powershell

Unleash the Power within with Powershell

Sean
The Energized Tech

We could spend all day taking screen shots and Polaroid pictures of the BIOS on workstations.   We COULD do that.

Or we could let Powershell and the Dell OMCI do the work.

Bios settings are stored in DCIM_BiosEnumeration.   But initially if you just did this

GET-WMIOBJECT DCIM_BiosEnumeration –namespace root\dcim\sysman

You’d have an unreadable screen.  Piping it into a Format-Table like this ALSO doesn’t help

GET-WMIOBJECT DCIM_BiosEnumeration –namespace root\dcim\sysman | FORMAT-TABLE

Because of the volume of data being returned.  Most of it I just don’t CARE what it is.  So I’ll save you the trouble.   I ran a GET-MEMBER on my machine to show the properties you care about

GET-WMIOBJECT DCIM_BiosEnumeration –namespace root\dcim\sysman | GET-MEMBER

Once I poked through the list I found the ones that seem to yield information consistently.     They are

AttributeName which is the name of the BIOS Setting

CurrentValue which is what it is set to now (numeric)

PossibleValues which is possible numeric values the BIOS Setting can have

PossibleValuesDescription which shows you the names DESCRIBING what those silly numbers mean

So running this script on a computer

Get-WmiObject -Namespace root\dcim\sysman DCIM_BiosEnumeration | Select-Object AttributeName,CurrentValue,PossibleValues,PossibleValuesDescription

Will show me all the settings on a Dell computer.   If I make a slight change and turn this into a script called GET-DELLBIOS.PS1

Param($Computername)

Get-WmiObject -Namespace root\dcim\sysman DCIM_BiosEnumeration –computername $Computername | Select-Object AttributeName,CurrentValue,PossibleValues,PossibleValuesDescription

I can now run a script with the –computername parameter and gather an inventory of all my Dell systems and their particular settings.

GET-DELLBIOS.PS1 –computername myremotecomputername

Pretty cool eh?  Now go forth and use your powers wisely.

With Great Powershell comes Great Responsibility

Sean
the Energized Tech

I was playing about with the Dell OMCI this morning (The free extension to WMI that allows you to manage Dell workstations with Powershell and/or vbScript (Choose your weapon!) and found an easy way to figure out where to start.

First run the following one liner.  Yeah the trick is pretty simple.

GET-WMIOBJECT –namespace root\dcim\sysman –list | SORT-OBJECT Name

All that does is list the various objects available to you sorted out.  

I never could figure out why there would usually 3 or 4 different names in WMI unless it’s meant to support the CIM standard somehow.   But what I found (like with the regular Windows ones) is there is usually only one name I care about.

In Windows it’s Win32_blahblahblah

In Dell OMCI it’s DCIM_blahblahblah

So if you want to just look for useful Dell stuff in WMI try filtering the list like this

GET-WMIOBJECT –namespace root\dcim\sysman –list DCIM* | SORT-OBJECT Name

To find objects alphabetically I just ran the GET-WMIOBJECT against a WHERE-OBJECT.  This showed me all the ones starting with the letter “a”. A smaller filtered list made it easier to play with

GET-WMIOBJECT –namespace root\dcim\sysman –list | WHERE { $_.Name –like ‘DCIM_a*’ }

Hmmm with an easier to pick list I started randomly plopping in names to see what they might be (OR you COULD just READ the DOCUMENTATION!)

But this was more fun

GET-WMIOBJECT –namespace root\dcim\sysman DCIM_view

GET-WMIOBJECT –namespace root\dcim\sysman DCIM_runningos

GET-WMIOBJECT –namespace root\dcim\sysman DCIM_AssetWarrantyInformation

Some of them were more interesting on a hardware level like DCIM_Battery which revealed the internal Details of the Dell battery including usage.

GET-WMIOBJECT –namespace root\dcim\sysman DCIM_Battery

Don’t forget you can apply –computername to all of these for accessing Remote Dell systems.   Now of course note that if the Dell DCIM is NOT installed, be prepared to catch this error.

GET-WMIOBJECT : Invalid namespace "root\dcim\sysman2"

At line:1 char:1
+ GET-WMIOBJECT -Namespace root\dcim\sysman DCIM_Battery
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Get-WmiObject], ManagementException
    + FullyQualifiedErrorId : GetWMIManagementException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
 

If you get that error, odds are pretty good either the Dell OMCI is not installed or that’s not a Dell you’re asking questions.

Play about with them and see what you discover, and FEEL the POWER of SHELL

Sean
The Energized Tech

Sometimes forgotten (mostly because I usually don’t see it in the downloads) is the Dell OMCI install for your Workstations.  If you haven’t been installing it, GET IT DEPLOYED NOW!

The Dell OMCI is an extension to Windows Management Instrumentation, which allows you to access very specific features of your Dell right down to the BIOS level.

Imagine being able to Manage settings in your BIOS like TPM or Wake on LAN.  Or PERHAPS head office has mandated all systems need to have a BIOS level password?

Can you imagine having to walk to 1,000 different machines and DO that? Hit me with a frying pan now.

To get it installed is just a matter of downloading the particular installer based upon whether you’re running a 64bit version of Windows or 32bit version.

You can download the media Here and push it via whichever method works best for you, and ensure it’s part of your Gold Dell image.

They provide you with some ok examples in Powershell but I found most actually didn’t work.  But here’s why, I think the scripts were tested on an older Dell OMCI version.

So here’s how you can work with them.  It’s all just a matter of using the GET-WMIOBJECT. 

They provided an example for Getting the status of Wake on LAN in the BIOS.  No matter what I did. It wouldn’t work.  Here’s the example.

gwmi DCIM_BIOSEnumeration -namespace root\dcim\sysman -filter "AttributeName='Wake On LAN'"

I personally prefer expand names to Aliases so I put that into my world first.

GET-WMIOBJECT DCIM_BIOSEnumeration -namespace root\dcim\sysman -filter "AttributeName='Wake On LAN'"

What did  I get? Nothing.  Nada.  Zippo.  $NULL.   But it also didn’t cough up an error.   So I went for something simpler.  Pull out the filter and see what I DID get

GET-WMIOBJECT DCIM_BIOSEnumeration -namespace root\dcim\sysman

My screen flooded with output.  This was better.  

So I ran that through GET-MEMBER and found some useful properties exposed like “AttributeName” and “CurrentValue”.   So I sorted it by AttributeName and used Select-Object to see what the actual names of the BIOS settings were when exposed  by Dell OMCI.

GET-WMIOBJECT DCIM_BIOSEnumeration -namespace root\dcim\sysman | SORT-OBJECT AttributeName | Format-Table AttributeName,CurrentValue

image

“AHA!” Jumping up like Einstein.   The name provided by Dell in the Example was WRONG. Wake On Lan ACTUALLY had Hyphens in the name. So a quick change in the example from this

GET-WMIOBJECT DCIM_BIOSEnumeration -namespace root\dcim\sysman -filter "AttributeName='Wake On LAN'"

to

GET-WMIOBJECT DCIM_BIOSEnumeration -namespace root\dcim\sysman -filter "AttributeName='Wake-On-LAN'"

to match the details EXPOSED by the Dell OMCI and suddenly

image

Now smiling and content I dived into the Dell examples provided to find out how to TURN it on.  

(gwmi DCIM_BIOSService -namespace root\dcim\sysman).SetBIOSAttributes($null,$null,"Wake On LAN","4")

Every time I ran this I got the following error causing me to scream like Charlie Brown missing the football. “Aiihhighihghghghighhigihh!!!!”

image

But then again, I wondered.  “Did they make the same mistake?” I looked and sure enough “Wake on LAN” was missing the Hyphens.

So again change the provided example from

(gwmi DCIM_BIOSService -namespace root\dcim\sysman).SetBIOSAttributes($null,$null,"Wake On LAN","4")

to a working one

(gwmi DCIM_BIOSService -namespace root\dcim\sysman).SetBIOSAttributes($null,$null,"Wake-On-LAN","4")

image

I rebooted my laptop to check and sure enough Wake on Lan was enabled.   I madly ran about our IT Group installing the Dell OMCI and turning on Wake On LAN settings to test.     Running /\/\/o\/\/’s script for Wake on LAN to test I had guys shutting down their machines.

*poof* *poof* *poof* Each machine magically accepted the Magic Packet.  

Now the cool part if you know anything about WMI is now that you know the NameSpace Dell has the OMCI in you can immediately pull up all the OTHER available extensions to query and export them to a CSV file like so.

GET-WMIOBJECT -namespace root\dcim\sysman –list | export-csv c:\powershell\dellomci.csv

Having a list of these is making it a bit more easy to poke through the pile.   I’m playing with enabling TPM remotely and I’ll post about that sometime soon.  

Remember, work SMARTER not HARDER with Powershell

Sean
the Energized Tech

Sorry, I hate long long extracted acronyms.  I LOVE the ISE but I would rather call it “The Powershell Editor” (Sorry Guys!)

In the first rendition of Powershell you had pretty much one choice, go find Notepad, Notepad++ or any standard Text editor or go “Hardcore” and build your content in CMD.EXE with COPY CON:

Later vendors like Quest introduced PowerGUI which at least gave us something to edit and debug with.

Then Powershell version 2 came along and somebody got smart.  “Hey we should at least provide a basic editor, one that can troubleshoot the script, view variables and drop in breaks”

The first ISE was “good”.  That’s a fare word. It didn’t crash, it didn’t suck but it wasn’t EVERYTHING we wanted.   But it was “good”

Now the gates have opened and with the Windows Management Framework 3.0 we have the new, the GREATLY improved, the “Oh come on, why didn’t you give us this in version 2” Powershell ISE.

I’m not poking fun.   I actually liked the ISE in Version 2 but for me personally, it was just another Notepad.  I used it occasionally but for my personal purposes it was lacking enough that I didn’t care.

In the new Powershell ISE I find myself launching it more.   Do you know why?  Look at it’s default setup.

image

By Default, launching the Powershell ISE gives you what APPEARS to be a normal Powershell Console, which I am most comfortable with.   But unlike the old ISE which had the stupid console screen, editor screen and output screen (I have no clue where that idea came from) this one is DEAD simple.

I can work in the “console” as happy as can be, but with a quick wave of my hand and a CTRL-R….

image

I have the ISE Editor Window directly above.   And since this whole thing is a GUI interface I can copy/paste with the mouse from the console straight into the editor.    This causes me to use the editor more than normal since I tend to live in the console, but if I want to create a create I just click and enable the editor directly above.

On the right is one of the best new features ever brought.  Technically it’s TWO new features.   In the Powershell ISE Version 3 they’ve introduced what is known as “Add-ons”.   Add-ons are just what they sound like, extensions and pieces you can “Add on” to the Powershell ISE to make it more useful and more to your liking.

The one built in is called the “Commands” Add-on which literally shows all available Cmdlets within the modules on your workstation and places them in a list on the right.

image

You can filter them out by selecting a pull down and choosing and individual module, click on a cmdlet and see the individual details of the paramters for the Cmdlet.

imageimageimage

But to make your life easier, the Powershell team introduced what I thought was the coolest feature.  Snippets.

Imagine blocks of code you might use on a regular basis.   The beginning of a cmdlet, a For-next loop, the basic format of Comment based Help.

The snippets are accessed by hitting CTRL-J in the ISE.  Click on a Snippet name and watch it populate the code automatically.

imageimage

….and yes Virginia, you CAN add on your own to the list.

This is just scratching the surface.  It has Intellisense on the Cmdlets as you type them including Variables and parameters.  it finally has an MRU list (Most recently used) to show scripts I have been editing.   IT SELF RECOVERS if the console crashes so you DON’T LOSE YOUR WORK!  You can even go out to Microsoft to pull down more Add-Ons.

It slices, it dices, it smashes, it trashes! It’s the NEW SLEDGE-O-MATIC!

Anyhow, take a look and see what you think.  It’s built in and part of Version 3 and I LIKE IT!

Feel the POWER of SHELL

Sean
The Energized Tech

powershell

Had to pull my list of MAC addresses together for a Wake on LAN script the other day.   The actual technique is posted by Marcus Van Orsow (/\/\o\/\/ The Powershell Guy) right here and lets you place a MAC address into a Powershell script to send the Wake on Lan to any device supporting it.

“…..coooooolllll…..” I said imagining Powering on hundreds of systems with a Single Script.

His original script looked like this

$mac = [byte[]](0x00, 0x0F, 0x1F, 0x20, 0x2D, 0x35)

$UDPclient = new-Object System.Net.Sockets.UdpClient
$UDPclient.Connect(([System.Net.IPAddress]::Broadcast),4000)
$packet = [byte[]](,0xFF * 102)
6..101 |% { $packet[$_] = $mac[($_%6)]}
$UDPclient.Send($packet, $packet.Length)

He later described some alternate techniques to build the object for the MAC address.  I found one I particularly liked which took a source address in TEXT and spun it into the MacAddress in the format the script liked.

$mac = [byte[]]("00-0F-1F-20-2D-35".split('-') |% {[int]"0x$_"})

So a Quick modification of the script with a simple param to pass in the MacAddress

param(
$MacAddress=””
)

$mac = [byte[]]($MacAddress).split('-') |% {[int]"0x$_"})


$UDPclient = new-Object System.Net.Sockets.UdpClient
$UDPclient.Connect(([System.Net.IPAddress]::Broadcast),4000)
$packet = [byte[]](,0xFF * 102)
6..101 |% { $packet[$_] = $mac[($_%6)]}


$UDPclient.Send($packet, $packet.Length)

And saving it as SEND-WOL.PS1 I was in business.  But a small problem.    Just HOW to get all of those MAC addresses?  I mean I could get about four Jolt Colas and go madly typing away, but really, the data is already THERE.

I will keep referring to this post because I love it.   Using Powershell to mine data from NETSH, the Admin Guy found a GREAT way to pull out DHCP data and make it useful.   Your DHCP scope not only contains the workstation name and current IP address.  It ALSO contains the MacAddress of the computer in question.

In my case, I didn’t want an HTML report.  I simply wanted a list of MAC addresses in USE and their particular Workstation names.  With this list in a simple CSV file I knew it would be a Powershell Oneliner I could use to Schedule a Wake On LAN for the entire Domain or targeted groups.

In his original script there was a static entry to the DHCP scope.  Believe it or not, I have 8 scopes to query for my task and different servers.   So the first modification was to take in parameters for the DHCP scope and the DHCPServer

param(
$DHCPScope,
$DHCPServer
)

So his first line now looked like this

$a = (netsh dhcp server $DHCPServer scope $DHCPScope show clients 1)

Next, an additional field for MAC in the properties.

$Row = "" | select MAC,Hostname,IP

I had to make sure the MAC address wasn’t removed so I commented out the line removing the MACaddress

#    $l = $l -replace '[0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}[:-][0-9a-f]{2}', ''

So far, so good.   But some extra cleanup was needed.  It was  producing some unwanted output.  Turns out I needed to make sure a dash became a comma.

    $l = $l -replace '-D-',','

And of course, make sure the Mac Address was added to the output this time

     $Row.IP = ($l.Split(","))[0]
    #Subnet mask not used, but maybe in a later version, so let's leave it in there:
    #$Row.SubNetMask = ($l.Split(","))[1]
   
    $Row.Mac = ($l.Split(","))[2]
    $Row.Hostname = ($l.Split(","))[3]
   

I removed the entire section for outputting to HTML.   His solution was already building a CSV file of the output.  I left that line in but dropped a RETURN to Return the $CSVfile value.   With that returned by the Script I could just build a single Variable rerunning the script each time supplying different values.

RETURN $CSVFile

Saving his script as GET-DHCPInfo.ps1 I was able to pull this off

$DHCPDATA+=(./GET-DHCPInfo.Ps1 –Dhcpscope ‘192.168.45.0’ –Dhcpserver ‘192.168.45.5’)
$DHCPDATA+=(./GET-DHCPInfo.Ps1 –Dhcpscope ‘192.168.22.0’ –Dhcpserver ‘192.168.22.5’)
$DHCPDATA+=(./GET-DHCPInfo.Ps1 –Dhcpscope ‘10.0.10.0’ –Dhcpserver ‘10.0.10.0’)

$DHCPDATA | export-csv C:\powershell\DHCPLIST.CSV

With this handy unsorted raw pile of MacAddresses in a text file I was able to pull off THIS with Marco’s Wake on lan Script.

IMPORT-CSV C:\powershell\DHCPLIST.CSV | foreach { (./SEND-WOL.PS1 –Macaddress $_.Mac)}

A mad cackling echoed throughout the office as staff twisted their heads ala “The Exorcist” while I screamed out “I HAVE WAKE ON LAN!!!!”

Now here’s another tip.  If you NEED the Macaddress and CAN do a Network scan you can use the “Advanced IP Lan Scanner” from Famatech (Free) which will probe a network and gather IP addresses and goodies.  You can export the output as CSV. 

Yes it’s free but not as automatic as Powershell.   It is handy for systems with Static IP addresses (like Servers) if you really don’t feel like typing.

Ah yes.  Life is good when armed with great technology that also happens to be free.

FEEL the Power of Shell

Sean
The Energized Tech

powershell

I love being able to manage things remotely.   The less I touch the console of server, the lower my chances of accidentally restarting it, doing something silly, you know like dumping a cup of coffee on a few Xeons.

In actual fact, I prefer having direct commands as well as working remotely.  I just want to go to a server and say “DO-THIS” and be done.  

The first time I saw a Web based version of Powershell it was from Quest.  My eyes lit up.

“I can manage the infrastructure from my Mobile device!” quickly picturing managing the entire environment from the comfort of a small secluded Sunny beach, surrounded by Margaritas.

When Microsoft announced Powershell Web Access and that it would work on most Browsers, I started making plans for my little beach location. “It’s part of the freaking OPERATING SYSTEM!”

The only way they can do better now?  I WANT DIRECT ACCESS on my WINDOWS PHONE !  Manage my entire Infrastructure SECURELY from my Windows Phone!

For those of you unaware, Powershell Web Access is Secure Powershell Console rendered within a standard web Browser, such as on your computer or Smartphone (yes, EVEN the iPhone, Blackberry and Android!)

It is also one of the simplest installs I have ever had to do.  It was effectively 4 simple steps.

  1. Add the Windows Powershell Web Access feature to Windows Server 2012
  2. Install the Web Application
  3. Create an Access Rule
  4. Apply an SSL Certificate

You can get very complicated on the install and even host it in your DMZ, but for basic internal access, four steps.  And truly, that’s where I PREFER my access to occur anyhow.

STEP 1 – Add the Windows Powershell Web Access feature

To install the feature you CAN go through the GUI and go “Clickity cllickity clicka click” *OR* being that it’s Powershell Web Access you can just run the “Add-WindowFeature” Cmdlet

ADD-WindowFeature WindowsPowershellWebAccess –includemanagementtools

The parameter “-includemanagementtools” will install the IIS management console.  If you PREFER you can skip this parameter and only install the Powershell Web Access feature.  Less installed means less to patch.

STEP 2 – Install the Web Application

You know, I’m certain somewhere there HAS to be a difficult way to do this, but it’s just a Cmdlet.  By default, with no additional parameters it will create the Powershell Web Access application just under the default Root folder of the IIS web site.  You CAN customize it (including alternate ports and locations) almost any way you like.  

But today is “INSTANT GRATIFICATION DAY!” just execute the following Cmdlet

INSTALL-PSWAWebApplication –force

STEP 3 – Create an Access Rule

This was the MOST DIFFICULT part of the whole scenario.   No really.  I actually had to READ the Help examples.   But run this line to allow Powershell Web Access to your Domain Admins.

Add-PSWAAuthorizationRule -RuleName 'Domain Admin Access' -UserGroupName 'CONTOSO\Domain Admins'  ConfigurationName * –Force -  -ComputerName 'SRV-PSWA' 

Really going left to right it states that

  • the rule who’s name is “Domain Admin Access” (This is completely descriptive, you could name it Flying Chinchilla’s if you liked, but it SHOULD make sense). 
  • The Active Directory Group “Domain Admins” in CONTOSO is being allowed access to ALL of the Powershell Web Access configurations (There’s only two at the time of this writing).  
  • We’re going to apply this rule on the Powershell Web Access server called “SRV-PSWA”.
  • Oh yes, and please “force” it through.   We don’t want to answer any silly questions.

STEP 4 – Apply an SSL Certificate

This is done within the IIS Console in the normal manner.   Apply a certificate to a particular port for the bindings (Typically 443) and force the Web application PSWA to enforce SSL

Here is an excellent article if you want to try and generate a self Signed cert in Powershell (which I think is cooler) but Powershell is all about getting home earlier.   In this case I just opt for the normal route in IIS to general a Self Signed certificate for testing purpose.    You’re only generating a certificate for Web hosting, so if you LIKE just generate a CERTificate request in IIS and pay a few bucks for a real one at your choice of SSL provider.

Me?  I’m cheap so I used the Self signed one and assigned it to the PSWA Web application and enforced the requirement for SSL

image

Once you’re done you can do something like this

https://SRV-PSWA/pswa

Login with your Domain Admin Credentials, specify the name of your Powershell Web Access server and take off!

It’s really THAT easy!

Need more details on Powershell Web Access?  Why not go straight to the source on Microsoft.com!

The Power of Shell is in YOU

Sean
The Energized Tech

I had a task laid down before me the other day.

“I am thy Boss!  Thou shalt seeketh out and Query the Lan for all Cisco Phones!  Thou shalt telleth me the MacAddress and primary Extension of each phoneth so that we might know what each user useth!”

Ok, it wasn’t quite like THAT, but it was a task we needed to do.

Now before you go this far, if you HAVE access to a Cisco SME, there is a way to pull this DIRECTLY from the Call Manager.  But I found out about this afterwards.   So why spoil our fun? Smile

So if you didn’t know, every Cisco IP phone has a built in web page.    That page reports most of the useful information about your phone, including Port speed, MAC address, Serial Number, location on Switch….

Sounds like some useful information doesn’t it?

So my first challenge, get all the IP’s of our Cisco phones.    That was actually easy.   Unless they are configured to using a Static IP (Bleeeaaaaccchhh!!!) they’re probably sitting in your DHCP pool.   For me, since I use a Microsoft DHCP server I grabbed a Script from “The Admin Guy” for pulling DHCP Server data into an HTML report.   It’s a solution I love since it leverages a legacy system (NETSH) and uses Powershell to produce better output.

I tweaked his script initially to just dump the data and give me the Mac addresses.  It was a messy dump since I initially goofed up (Did I mention we had to pull this answer quickly?) but I had a list of IP addresses and hostnames to start with.

If you’re looking for the Cisco IP Phones in the DHCP pool, just seek the systems starting with SEP and the rest is usually the phone Mac address.

Now the fun part. digging through the web page in the phone.

For this task I had Powershell 3 to play with so I saved some time in fiddling with browsers by using the new INVOKE-WEBQUEST Cmdlet

$Phone=(INVOKE-WEBREQUEST 'http://192.168.45.54/CGI/Java/Serviceability?adapter=device.statistics.device'

Now I had something to play with.   Since I don’t play with HTML much, I tried examining the “RawContent” property to see if it had what I was looking for.  In my first attempt I was querying the Webpage on the phone which displayed the MAC Address.   It actually displays the word “MAC Address” on the display so I figured I would have a shot of it displaying the data in some reasonable pattern…. hopefully.

To do this initially I dumped the data to a file and cheated using “Notepad.exe” to see if the data was there.   No, I am NOT a master of Regex (and wish I was)

$Phone.RawContent | out-file c:\powershell\test.txt

NOTEPAD C:\Powershell\test.txt

Sure enough I found the data was stored in a consistent pattern in the HTML document.   It was always after the word “MAC Address” followed by some HTML data.   I used this as my Search parameter for a SELECT-STRING

$locationmac=$phone.RawContent | Select-String -Pattern 'MAC Address</B></TD><td width=20></TD><TD><B>'

Now with a consistent way to find the Mac address and the Index to where it could be pulled from a web page, a simple For loop to pull out the 12 Digits of the MAC address.

$startmac=$locationMac.Matches.Index+$LocationMac.Matches[0].Length

for ($x=0;$x -lt 12; $x++) {

$MacAddress=$MacAddress+$Phone.Rawcontent[$Startmac+$x]

}

Querying the rest was a matter of finding which web page exposed the data and a similar pattern which would be nothing more than

Use SELECT-STRING to find data header location.

Pull data out for For loop

Now the rest of the data wasn’t as nice as the Mac Address, not all phones had the same number of digits for the serial number, not all extensions had the same number of digits.   For that I ran a DO Until loop to query data until it hit the first part of new HTML (Which in this case consistently started with a “<”)

Now the fun bit.   RETURNING that Object.   In Powershell Version 3 there is a really cool feature June Rogers showed me at Teched called '[pscustomobject]’ which lets you simply define a New Powershell custom object in one simple line.

In my case I just wanted to return my data so I was able to do this as one simple line in Version 3

return [pscustomobject]@{PhoneDN=$PhoneDN;MacAddress=$MacAddress;Serialnumber=$SerialNumber;SwitchSpeed=$Switchspeed;SwitchPosition=$SwitchPosition}

This would return an Object with 5 pieces of data I had queried as one Powershell Object with 5 properties.

The end result was a script looking like this.   I haven’t dropped in any error checking but it worked ok the first time with a CSV file of IP Addresses being piped to this script.

Enjoy and FEEL the Power of Shell – It’s in YOU

Sean
The Energized Tech

param(
[string]$IPAddress='192.168.45.54'
)

#Data to be pulled from Phone

$MacAddress=$NULL
$SerialNumber=$NULL
$PortLocation=$NULL
$PortSpeed=$NULL
$SwitchPosition=$NULL
$SwitchSpeed=$NULL
$PhoneDN=$NULL

#URL on Cisco Phone with Page containing MAC address

$PhoneRequest='http://'+$IPAddress+'/CGI/Java/Serviceability?adapter=device.statistics.device'

$phone=Invoke-WebRequest $PhoneRequest

#Find where the MAC address header is in the HTML document

$locationmac=$phone.RawContent | Select-String -Pattern 'MAC Address</B></TD><td width=20></TD><TD><B>'

# Use the Index of the data within the document

$startmac=$locationMac.Matches.Index+$LocationMac.Matches[0].Length

# Mac address is 12 digits, grab them all into a string

for ($x=0;$x -lt 12; $x++) {

$MacAddress=$MacAddress+$Phone.Rawcontent[$Startmac+$x]

}

#Serial number is on the same page as the MAC Address

$locationserial=$phone.RawContent | Select-String -Pattern 'Serial Number</B></TD><td width=20></TD><TD><B>'
$startserial=$locationserial.Matches.Index+$Locationserial.Matches[0].Length

#Reset counter

$x=0

# This is different, pull everything until you hit new HTML data
# Look for a “<”

do { $SerialNumber=$SerialNumber+$Phone.Rawcontent[$StartSerial+$x]; $x++; } while ($Phone.Rawcontent[$StartSerial+$x] -ne '<')

$locationDN=$phone.RawContent | Select-String -Pattern 'Phone DN</B></TD><td width=20></TD><TD><B>'
$startDN=$locationDN.Matches.Index+$LocationDN.Matches[0].Length

#Reset counter

$x=0

# Same process, but find the phone DN (Primary Extension)

do { $PhoneDN=$PhoneDN+$Phone.Rawcontent[$StartDN+$x]; $x++; } while ($Phone.Rawcontent[$StartDN+$x] -ne '<')

# Now we look for the Port Speed and the Switch it sits on

$PortRequest='http://'+$IPAddress+'/CGI/Java/Serviceability?adapter=device.statistics.port.network'

$portdata=Invoke-WebRequest $PortRequest

$locationswitch=$portdata.RawContent | Select-String -Pattern 'CDP Neighbor Port</B></TD><td width=20></TD><TD><B>'

$startswitch=$locationswitch.Matches.Index+$Locationswitch.Matches[0].Length

$x=0

do { $SwitchPosition=$SwitchPosition+$PortData.Rawcontent[$StartSwitch+$x]; $x++; } while ($portdata.Rawcontent[$StartSwitch+$x] -ne '<')

$locationspeed=$portdata.RawContent | Select-String -Pattern 'Port Information</B></TD><td width=20></TD><TD><B>'

$startspeed=$locationspeed.Matches.Index+$Locationspeed.Matches[0].Length

$x=0

do { $SwitchSpeed=$SwitchSpeed+$PortData.Rawcontent[$Startspeed+$x]; $x++; } while ($portdata.Rawcontent[$StartSpeed+$x] -ne '<')

# Return all data as a Powershell v3 Custom Object

return [pscustomobject]@{PhoneDN=$PhoneDN;MacAddress=$MacAddress;Serialnumber=$SerialNumber;SwitchSpeed=$Switchspeed;SwitchPosition=$SwitchPosition}

Why I LOVE Powershell

| | TrackBacks (0)

I LOVE POWERSHELL.

Is this something I've said before? Probably, and for good reason.

Powershell is many things to many people. An easier way to extend .NET applications to Infrastructure. A system which enables the ITPro to aid his Developer friend by building the tools they need.

It is a scripting AND Managment console. It's a piece of software that can interact, work and be used by legacy systems.

It's a big box of digital Lego blocks and Mechano all in one!

This weekend I had to help a friend out from Around the Clock I.T. Solutions. The client wanted to Power ON every computer at a certain time to ensure updates occurred.

"How long would that take to go setup?"

I smiled and replied "About 15 minutes, that' a Powershell script"

So poking online I found the script written by "The Powershell Guy" Marcus Van Orsow, to trigger a Wake on Lan with the Mac Address. Next was to pull down another cool script from “The Admin Guy” to parse DHCP data from Netsh.

With some minor changes I had it pulling the MAC address and outputting to an object.

With these two scripts and very little additional effort I now have a Wake on Lan SOLUTION I can use ANYWHERE!

All thanks to the Power of Powershell.

This is why I Love Powershell. When you NEED to produce those last minute needed solutions, it's simple to build and modify other scripts to meet your needs.

Oh yeah, I'm feeling it.

THE pOwer of Shell :-)

Ran across an interesting one today.

In versions of Outlook connecting to a Microsoft Exchange server you may not see the "Recover Deleted Items" for what is referred to as "Hard Deleted".   (Items which are only recoverable from the Exchange Server Database)

This is normal.   And you'll do a Bing online (No I don't use the "G" word, it feels.... dirty ;) ) and find you need to create a DWORD Registry entry called "DumpsterAlwaysOn" under with a value set to 1 under

Hkey_Local_Machine\Software\Microsoft\Exchange\Client\Options

Now I swear, I have dont this a kajillion zillion times and this has ALWAYS WORKED.  ALWAYS! (No really, that many times!  I swear!)

.....UNTIL TODAY! (Cue Dramatic Music - Dun Dun Duuuuuuuuhhhhhh!!!!!!)

Today the "you know who" gods who staring down with miscievous evil grins as I entered it and couldn't get it to work in Outlook 2010.   I was dumbfounded.

I restarted the application, terminated communicator and restarted the application, rebooted the computer, quintuple checked my spelling and was about to place my finger through the display until I realized something small.  Something SO important it was missed.

I was running the 32 bit version of Outlook on the 64 bit version of Windows 7.  Which meant I was running the 32 bit version of MAPI.

"DOH!" I screamed in the middle of the office as I remembered to navigate to the MOST important key for 32bit applications on a 64bit Windows platform.

"Wow6432Node"

So I found it's twin.   The actual key that SHOULD have been edited since a 32 bit on 64 bit platform runs on Wow mode (Windows on Windows) and quickly added the key under

HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Exchange\Client\Options

It of course immediately worked afterwards.   My co workers quickly breathed a sigh of relief as we picked up all the sheetrock that fell down with my "Doh!"

Just remember the magic words from Douglas Adams when problems happen.

"Don't Panic"

Sean
The Energized Tech