PowerShell Answers

Adventures in PowerShell

About the author

Author Name is someone.
E-mail me Send mail

Recent posts

Recent comments

Don't show

Authors

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2008

PowerShell everywhere!

I just saw this on Micosoft.Public.Windows.Powershell

 

PASH - PowerShell open source reimplementation for "others" (Mac, Linux, Solaris, etc...) and Windows (including Windows Mobile and Windows CE)

http://pash.sourceforge.net/

It just gets better and better :-)

 Trevor

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by tb on Tuesday, April 08, 2008 5:11 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Custom objects, custom formatting

One of the things that comes up quite often in my PowerShell classes is using your own .Net types so I though I'd put up a couple of entries based on a demo that I do.

I've put a zip file with all of the code mentioned in these posts into my download area.

I created a small .Net assembly containing two types, Bank and Account.

and compiled them into a file called Accounts.dll.

Now I can use Reflection.Assembly to load the dll

and create and use objects from the assembly

In the next post I'll add a custom format file so that negative bank account balances are displayed a (1000) rather than -1000.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by tb on Monday, March 03, 2008 2:13 AM
Permalink | Comments (0) | Post RSSRSS comment feed

PowerShell support in SQL 2008

I've just been looking at the PowerShell support and it looks interesting if a little limited - as has been stated in Dmitry’s PowerBlog.

You invoke PowerShell from SQL Server Management Studio by right clicking on a node in the tree and choosing 'Start PowerShell'. This runs 'SQLPS.exe' and starts the shell. One thing that caught me was that the resulting shell has some standard cmdlets missing. Add-PSSnapin, Get-PSSnapin, Remove-PSSnapin and Export-Console seem to have gone AWOL.

SQL Books Online states that the SQL snapins are

  • Microsoft.SqlServer.Management.PSProvider.dll
  • Microsoft.SqlServer.Management.PSSnapin.dll

As these are just regular snapins you can load them into the standard PowerShell host as follows -
First register the snapins using the .Net utility installutil with the commands

set-alias installutil $env:windir\Microsoft.NET\Framework\v2.0.50727\installutil
cd "c:\Program Files\Microsoft SQL Server\100\Tools\Binn"
installutil Microsoft.SqlServer.Management.PSProvider.dll
installutil Microsoft.SqlServer.Management.PSSnapins.dll

and check that everything is OK


Registering SQL snapins

Then load the snapins

Installing the SQL snapins

and voila SQL support is enabled

SQL support working

Don't forget to remove and unregister (installutil /u) the snapins when you want to remove the CTP.

Currently rated 5.0 by 2 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: PowerShell | SQL 2008
Posted by tb on Monday, February 25, 2008 1:23 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Getting through a proxy server with PowerShell

When we were looking at using the System.Net.WebClient class to retrieve web pages the question "how do you use this when you have to go through a proxy server and provide credentials?" came up.

A little bit of exploration with get-member and some digging in MSDN revealed that

  • the System.Net.WebClient class has a proxy property that can be set to an instance of the System.Net.WebProxyClass
  • the System.Net.WebProxyClass has a credentials property that can be set to an instance of any object that implements the ICredentials interface
  • The class System.Net.NetworkCredential implements ICredentials
  • the get-credential cmdlet returns a System.Management.Automation.PSCredential object
  • the PSCredential class has a method called GetNetworkCredential that returns a System.Net.NetworkCredential object - just what we need :-)

  Putting all of that together gives us this script which will ask for credentials and feed them to a proxy server.

[void][System.Reflection.Assembly]::LoadWithPartialName("System.Net")
#
# Create a proxy object
#
$proxy = new-object System.Net.WebProxy
#
# Grab some credentials and store them in the proxy object
#
$cred = get-credential
$proxy.credentials = $cred.GetNetworkCredential()
#
# Off to the web
#
$WebClient = new-object System.Net.WebClient
$WebClient.proxy = $proxy
$url = "http://www.microsoft.com"
$content = $WebClient.DownloadString($url)

It just goes to show how great the combination of PowerShell and the .Net framework is!

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by tb on Monday, January 07, 2008 3:53 AM
Permalink | Comments (0) | Post RSSRSS comment feed

A forms designer for PowerShell

I've just finished a great week teaching Mastering PowerShell for HBOS and a couple of interesting things came up.

When I teach the Windows.Forms module I usually show how easy it is to use one of the Visual Studio Express editions to build a form and then translate the designer generated code into PowerShell. This time however one of  the delegates pointed me at the Admin Script Editor which has a forms designer that generates native PowerShell script code :-)

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by tb on Monday, January 07, 2008 3:51 AM
Permalink | Comments (0) | Post RSSRSS comment feed

The PowerShell 2.0 CTP is here!

You can download it from here

There are a couple of new posts from the PowerShell team that give some more information about this preview release

The first thing that catches my eye is a new version of get-wmiobject that adds in some of the sorely missed functionality of the COM interface to WMI. Hopefully the WMI interface also has some bug fixes.

Congratulations to the PowerShell team.

 

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: PowerShell | CTP
Posted by tb on Monday, January 07, 2008 3:50 AM
Permalink | Comments (0) | Post RSSRSS comment feed

The PowerShell 2.0 CTP is nearly here!

Check out these messages from Jeffrey Snover

Start building your VMs :-)

 

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: PowerShell | CTP
Posted by tb on Monday, January 07, 2008 3:48 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Launching PowerShell Scripts in Response to WMI Events

This turns out to very straightforward, the key is to use the CommandLineEventConsumer class. It allows you to launch any program in response to a WMI event. In order to use it you only need to set two properties (although there are many more to explore)

  1. Name - a unique name for your class instance
  2. CommandLineTemplate - the command you want to run

As we want to launch a PowerShell script the command line would need to be something like

powershell.exe -command C:\temp\myscript.ps1

This would run the script myscript.ps1 and pass it any parameters that are added to the command line. Within the script you can access the parameters via the $args array.

A Working Example

Lets say that we wanted to stop people running Solitaire on their PCs - it's mean but hey, we're admins! The PowerShell cmdlet stop-process will kill a process if we supply the process ID so we'll pass that out from WMI to the script and pick it up via $args.

stop-process $args[0]

As before you need to create a filter and a consumer and join them together. So this code creates a filter that looks for instances of Solitaire starting up

$EFClass = [wmiclass]"\root\subscription:__EventFilter"
$ef = $EFClass.CreateInstance()
$ef.Name = "NewProcessFilter"
$ef.Querylanguage = "WQL"
$ef.Query = "select * from __InstanceCreationEvent within 5 where targetinstance isa 'Win32_Process' and targetinstance.name = 'Solitaire.exe'"
$ef.EventNamespace = "root\cimv2"
$ef.put()

Next we create a consumer, using the CommandLineEventConsumer class. %TargetInstance.Handle% picks up the process ID from the win32_process object that triggered the event and adds it onto the end of the PowerShell command line.

$CLECClass = [wmiclass]"\root\subscription:CommandLineEventConsumer"
$clec = $CLECClass.CreateInstance()
$clec.Name = "RunPowerShell"
$clec.CommandLineTemplate = "powershell.exe -command C:\temp\myscript.ps1 %TargetInstance.Handle%"
$clec.put()

and finally join them together with an instance of the __FilterToConsumerBinding class

$FCBClass = [wmiclass]"\root\subscription:__FilterToConsumerBinding"
$fcb = $FCBClass.createinstance()
$fcb.Consumer = $clec.__Path
$fcb.Filter = $ef.__Path
$fcb.put()

Now every time you start Solitaire the PowerShell script myscript.ps1 will run and Solitaire will be terminated :-)

Note

You might get the same errors that I noted in an earlier post when you invoke the put method. This is a known bug in PowerShell 1.0 and will be fixed in v2.0. The workaround for now is to keep invoking put until it works.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: events | PowerShell | WMI
Posted by tb on Monday, January 07, 2008 3:41 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Make it stop, make it stop!

The easiest way to stop event processing is to delete the binding between a filter and a consumer. In WMI terms the '__FilterToConsumerBinding' class is known as an association class, all it does is link together two other classes. Association classes are a pain to connect to directly so it's simpler to use another type of WQL query that returns the association class connected to your filter or consumer. The code below does exactly that and once you have the associator you can invoke its delete method to break the link. Do bear in mind that a filter or consumer may be associated with more than one other filter or consumer so you might get an array of results rather than just one.


$AssociatorInstance = gwmi -query "REFERENCES OF {__EventFilter='NewProcessFilter'}" -namespace "root\subscription"
$AssociatorInstance.delete()

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by tb on Monday, January 07, 2008 3:39 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Configuring WMI Event Handling with PowerShell

PowerShell provides a helpful type accelerator '[WMICLASS]' that makes using these WMI classes extremely easy.

Lets say that we wanted to log to a file every process that was created on a machine.

First we need to create our filter. To do this we connect to the '__EventFilter' class, create a new instance, set it's properties and save it into WMI. Note - you need admin rights to write into the WMI store so you will need to run PowerShell as administrator for these scripts to work. There is no way to provide alternative credentials when you are using the type accelerator. Get-WmiObject does support a credential parameter but it doesn't work on local connections and there's no way to use the credential when you invoke 'Put' on the new class instance.

The code below creates a filter that will check the '\root\cimv2' namespace every 5 seconds for new instances of the 'Win32_Process' class'

$EFClass = [wmiclass]"\root\subscription:__EventFilter"
$ef = $EFClass.CreateInstance()
$ef.Name = "NewProcessFilter"
$ef.Querylanguage = "WQL"
$ef.Query = "select * from __InstanceCreationEvent within 5 where targetinstance isa 'Win32_Process'"
$ef.EventNamespace = "root\cimv2"
$ef.put()

Now we create the event consumer - in this case we're going to use the LogFileEventConsumer. As before we attach to the appropriate class, create an instance, set its properties and store the new instance. Note the use of a string template in the text property. This allows us to pull out properties from the object that caused the event - in this case an instance of Win32_Process.

$ECClass = [wmiclass]"\root\subscription:LogFileEventConsumer"
$lfc = $ECCLass.createinstance()
$lfc.Name = "MyLogFileConsumer"
$lfc.FileName = "c:\temp\Win32Process.log"
$lfc.Text = "Process %TargetInstance.Name% was created on %TargetInstance.CreationDate%"
$lfc.put()

And then to start everything off we connect the filter and consumer using an instance of the '__FilterToConsumerBinding' class. This class requires that you give it the unique identifiers of the filter and consumer that you want to connect. You can always get this from a WMI object by referencing its '__Path' property.

$FCBClass = [wmiclass]"\root\subscription:__FilterToConsumerBinding"
$fcb = $FCBClass.createinstance()
$fcb.Consumer = $lfc.__Path
$fcb.Filter = $ef.__Path
$fcb.put()

And that's it! WMI will now record every process that starts on your machine until you delete the binding.

But it doesn't work!

You may find that when you try to invoke the 'put' method on a WMI object you get an error like this

WMIError

If that happens just invoke 'Put' again (and again and again) and it will work - eventually!

 WMIWorking

You might also find that when you try to store the paths of your filter and consumer into the binding object you get nulls rather than  valid paths. Retrying a few times will fix this. I've seen this behaviour on XP and Vista. There's definitely something odd going on here but I haven't tracked it down yet.

 

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by tb on Monday, January 07, 2008 3:34 AM
Permalink | Comments (0) | Post RSSRSS comment feed