Archive for the “.NET” Category

This is actually a fairly simple task that many people have done in many different languages. However, I thought it would be useful to share for the sake of showing how .NET can do a lot of tedious work for us.

IP Addresses are made up of 32 bits. Subnet masks are 32 bits as well. The subnet mask is what is used to determine where the Network ID ends and the host ID begins. Masks must have contiguous 1’s. If there is a 1 in the mask, then the corresponding bit in the IP Address is part of the Network ID. If there is 0 in the mask, the corresponding bit in the IP Address is part of the host ID.

So obviously there is going to be a lot of binary math, which any good network engineer can do. However, if you can get it for free, even better!

There is a type in .NET called System.Net.IPAddress that has several useful properties. The one I will focus on is Address.

image

Using the Address property and some bitwise operators in PowerShell, we can come up with a function pretty quickly. The –and and –or operators are pretty commonplace in the world of PowerShell but there is occasionally a need to do a compare of two numbers at the bit level. This is done with the –band and –bor operators. I may be off but if memory serves, using –bor and –band you can build any other bit function like xor. I won’t event think about K-maps.

So with all that, here is some code:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
Function Test-SameSubnet {
param (
[parameter(Mandatory=$true)]
[Net.IPAddress]
$ip1,

[parameter(Mandatory=$true)]
[Net.IPAddress]
$ip2,

[parameter()]
[alias("SubnetMask")]
[Net.IPAddress]
$mask ="255.255.255.0"
)

if (($ip1.address -band $mask.address) -eq ($ip2.address -band $mask.address)) {$true}
else {$false}

}

The Address property is the binary number that represents the IP Address. Doing a bitwise AND with a mask will tell us if they are in the same subnet. I have a default value of 255.255.255.0 for the mask, or /24 if you prefer CIDR notation, but you can specify it as a parameter if you like.

 image

Comments 1 Comment »

We can use C#  quite easily with the Add-Type Cmdlet. With the -language parameter, you can also use VB .NET. However,if you are into functional programming and like F#, you can use that as well, although not quite as easily.

First, go and download the September 2008 CTP of F#. Once you have this installed, launch the 32 bit version of PowerShell. I’m using a 64 bit Vista machine and I had problems with the 64 bit version of Powershell with one line which I will get to in a bit. I think it has to do with the F# CodeDom Provider, not with PowerShell itself.

The F# CodeDom.dll was installed in C:\Program Files (x86)\FSharp-1.9.2.9\bin for me. Your mileage may vary. Anyway, cd into the bin directory of F# and you will find a file called FSharp.Compiler.CodeDom.dll. Once you are there, you can run the following lines to load up the F# Code Provider.

Add-Type -Path FSharp.Compiler.CodeDom.dll
$provider = New-Object Microsoft.FSharp.Compiler.CodeDom.FSharpCodeProvider
$fsharpCode = @"
let sample = [1;2;3;4;5;6;7]
"@
$fsharpType = Add-Type -TypeDefinition $fSharpCode -CodeDomProvider $provider -PassThru |
where { $_.IsPublic }
$fsharpType::sample

When you call Sample on $fsharpType, it will return the array with numbers 1 through 7.

For some reason when I ran this on a 64 bit I get the following error when I try to add the type with typeDefinition $fsharpCode on line 6

Add-Type : The system cannot find the file specified
At line:6 char:23
+ $fsharpType = Add-Type <<<<  -TypeDefinition $fSharpCode -CodeDomProvider $provider -PassThru | where { $_.IsPublic }
    + CategoryInfo          : NotSpecified: (:) [Add-Type], Win32Exception
    + FullyQualifiedErrorId : System.ComponentModel.Win32Exception,Microsoft.PowerShell.Commands.AddTypeCommand

If you are into this sort of thing, have fun!

Comments 4 Comments »

I’ve been working on a Winform that I use in a PowerShell script and I needed to display HTML in the form. As I was playing with the form designer in Visual Studio, I found a Web Browser Control that I thought would do the trick. It worked great in C# but when I ported it over to PowerShell, I found I had problems with STA and MTA. The WebBrowser Control will only work in STA mode. Not so good for PS V1 which only runs in MTA.

Marco Shaw reminded me of a blog post on the PowerShell Team Blog about a cmdlet that could run a command in STA mode. This worked like a champ as soon as I downloaded the code and built the Snapin. I was able to run invoke-apartment STA ShowWinform and everything was great.

But then I tried to parameterize my function and it got a little more hairy. The Invoke-Apartment cmdlet takes two parameters, the first is the apartment you want to use (MTA or STA) and the second is called expression that is a STRING.

I wanted to pass in something like this

invoke-apartment –apartment STA –expression “ShowWinform –html <h1>Hello World</h1>”

This blew up in my face, and I was getting parsing errors and all kinds of weird stuff.

Now mind you, I am not a developer, but PowerShell has given me enough background to be willing to crack open some C# code now and then, really just enough to make me dangerous.

So I started looking at the invoke-apartment cmdlet’s parameters. I saw that both parameters were of type string. I thought, hmm, I wonder what would happen if I set them to ScriptBlock instead of String.

I poked around the code a bit more to see where these parameters were being used and gave it a shot. To my utter amazement, the thing actually compiled. Furthermore, to my utter, utter amazement, it actually did what I was hoping. It now took a ScriptBlock instead of a string and I wasn’t getting my parsing errors. The only trick was that I had to wrap my expression in curly braces so PowerShell would know that it was a ScriptBlock.

So now the following code totally worked in PowerShell.

invoke-apartment –apartment STA –expression {“ShowWinform –html <h1>Hello World</h1>”}

The point of all of this is that I love how PowerShell has enabled me to get comfortable enough with C# so that I can look at something and tweak it to make it work for what I needed to do.

I am not saying that all admin should crack open C#, but if you haven’t used a cli yet, fire up PowerShell. If you have played with the cli, but haven’t written any functions, write one. If you haven’t written any scripts, take some of your functions and put them together in a script. It’s all about the journey. PoweShell has really helped take a bunch of next steps.

Oh yeah, and if you are interested, here is the source code with my modifications. Given the code below and reading this blog post, you can build your own Invoke-Apartment cmdlet and Snapin.

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.ComponentModel;
using System.Configuration;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
 
 
namespace Powershell.Blogs {
 
    /// <summary>
 
    /// Class implemeting Invoke-Apartment
 
    /// </summary>
 
    [Cmdlet("Invoke", "Apartment")]
 
    public sealed
 
    class
 
    InvokeApartmentCommand : PSCmdlet {
 
        internal class ExecutionResult {
 
            private object output;
 
            private Exception error;
 
 
 
            public Object Output {
 
                get { return output; }
 
                set { output = value; }
 
            }
 
 
 
            public Exception Error {
 
                get { return error; }
 
                set { error = value; }
 
            }
 
        }
 
 
 
        #region Private Data
 
 
 
        private ManualResetEvent waitHandle;
 
 
 
        private Runspace runspace;
 
        private Runspace Runspace {
 
            get {
 
                return runspace;
 
            }
 
 
 
            set {
 
                runspace = value;
 
            }
 
        }
 
 
 
        #endregion
 
 
 
        #region parameters
 
 
 
        private ScriptBlock command;
 
        private ApartmentState apartment = ApartmentState.MTA;
 
 
 
        /// <summary>
 
        /// Apartment to run the cmdlet int
 
        /// </summary>
 
        [Parameter(Position = 0, Mandatory = true)]
 
        public ApartmentState Apartment {
 
            get { return apartment; }
 
            set { apartment = value; }
 
        }
 
 
 
        /// <summary>
 
        /// Command to execute.
 
        /// </summary>
 
        [Parameter(Position = 1, Mandatory = true, ValueFromPipeline = true)]
 
        public ScriptBlock Expression {
 
            get { return command; }
 
            set { command = value; }
 
        }
 
 
 
        #endregion parameters
 
 
 
        protected override void BeginProcessing() {
 
            // Set the runspace
 
            Runspace = Runspace.DefaultRunspace;
 
        }
 
 
 
        /// <summary>
 
        /// For each record, execute it, and push the results into the 
 
        /// success stream.
 
        /// </summary>
 
        protected override void ProcessRecord() {
 
            ExecutionResult result = new ExecutionResult();
 
 
 
            if (Thread.CurrentThread.GetApartmentState() == apartment) {
 
                // Since the current apartment state is same as the one requested
 
                // do the work in same thread.
 
                DoWork(result);
 
            } else {
 
                // the apartment state is different..perform the task in 
 
                // a differnt thread.
 
                Thread executionThread = new Thread(new ParameterizedThreadStart(PerformExecution));
 
                executionThread.SetApartmentState(apartment);
 
 
 
                // Create a handle to wait for completion
 
                waitHandle = new ManualResetEvent(false);
 
                executionThread.Start(result);
 
 
 
                waitHandle.WaitOne();
 
            }
 
 
 
            if (null != result.Error) {
 
                throw result.Error;
 
            }
 
 
 
            if (null != result.Output) {
 
                WriteObject(result.Output);
 
            }
 
        }
 
 
 
        private void PerformExecution(object outputToWriteTo) {
 
            ExecutionResult result = (ExecutionResult)outputToWriteTo;
 
 
 
            // Use the runspace to execute the script
 
            Runspace.DefaultRunspace = Runspace;
 
 
 
            DoWork(result);
 
 
 
            if (null != waitHandle) {
 
                waitHandle.Set();
 
            }
 
        }
 
 
 
        private void DoWork(ExecutionResult result) {
 
            try {
 
                //ScriptBlock myScriptBlock = InvokeCommand.NewScriptBlock(Expression);
                ScriptBlock myScriptBlock = Expression;
                result.Output = myScriptBlock.InvokeReturnAsIs(null);
 
            } catch (Exception e) {
 
                result.Error = e;
 
            }
 
        }
 
 
 
    }
 
 
 
    /// <summary>
 
    /// Create this sample as a PowerShell snap-in
 
    /// </summary>
 
    [RunInstaller(true)]
 
    public class InvokeApartmentPSSnapIn : PSSnapIn {
 
        /// <summary>
 
        /// Create an instance of the InvokeApartmentPSSnapIn
 
        /// </summary>
 
        public InvokeApartmentPSSnapIn()
 
            : base() {
 
        }
 
 
 
        /// <summary>
 
        /// Get a name for this PowerShell snap-in. This name will be used in registering
 
        /// this PowerShell snap-in.
 
        /// </summary>
 
        public override string Name {
 
            get {
 
                return "InvokeApartment";
 
            }
 
        }
 
 
 
        /// <summary>
 
        /// Vendor information for this PowerShell snap-in.
 
        /// </summary>
 
        public override string Vendor {
 
            get {
 
                return "PowershellBlog";
 
            }
 
        }
 
 
 
        /// <summary>
 
        /// Description of this PowerShell snap-in.
 
        /// </summary>
 
        public override string Description {
 
            get {
 
                return "This is a PowerShell snap-in that includes the invoke-apartment cmdlet.";
 
            }
 
        }
 
    }
 
}
 

Comments 6 Comments »

I mentioned earlier that I had told a colleague about using Hashtables in PowerShell and C#.  Later on in the afternoon, he came across a situation where he needed to generate a random string of characters.

He came up with this little snippet of code.  (I think he may have a been a little high on Hash . . . . . tables)

   1: function new-array {$args}                                                                                        
   2: $CharacterArray = new-array A B C D E F G H I J K L M N O P Q R S T U V X Y Z;                                    
   3: $CharacterHashTable = new-object System.Collections.Hashtable                                                                                                                                                                     
   4: for ($i=0; $i -ilt $CharacterArray.Count; $i++) {$CharacterHashTable.Add($i, $CharacterArray[$i])}                
   5: $randomNumber = new-object System.Random                                                                          
   6: $randomCharacter = $CharacterHashTable[$randomNumber.next(0,25)]                         

“Wow!  That is great!  You basically reinvented ASCII !”

Then I showed him this neat little trick :)

   1: PS >  [char]65
   2: A

He came back with these two lines to generate a random character.

   1: $randomObject = New-Object System.Random
   2: $randomChar = [char]$randomObject.next(65,90)

It turns out that if you know ASCII exists, it can indeed be used to generate random characters :)

However, I have to give some credit for coming up with a neat little subset of ASCII in a couple lines of PowerShell. Not too shabby!

Comments 1 Comment »

I have an intern working with us and he is writing some PowerShell and C# WinForms to automate some of our administrative tasks. He had a problem with a C# app and when he started asking me about it, it sounded like a hash table was just what the doctor ordered.

He had seen hash tables in PowerShell but wasn’t quite sure how they would work in C# (he had only cracked open C# maybe 5 weeks ago). Rather than firing up Visual Studio and typing in a bunch of “blah-blah/yadda-yadda” I was able to demo a “C# version” of hash tables in PowerShell.

Once he saw this, he was able to understand how to use hash tables in C#. 

   1: 268 >  $hash = New-Object System.Collections.Hashtable
   2: 269 >  $hash.Add("one",1)
   3: 270 >  $hash
   4:  
   5: Name                           Value
   6: ----                           -----
   7: one                            1
   8:  
   9:  
  10: 271 >  $hash.one
  11: 1
  12: 272 >

I just love how PowerShell is continuing to bridge a gap between Developers and Admins. These are obviously different disciplines and both require different skills, but the more we can learn about each one, the more effective we can be in our respective roles.

Comments 4 Comments »

There has been a lot of talk in the last couple weeks about using WPF to build UI’s for Powershell. Just to name a few

Powershell Team’s Series on WPF

Joel Bennet’s Huddled Masses Series on WPF

I think this is great and I can’t wait to see what we all come up with.

As we begin to build these graphical tools on top of Powershell, UI and user experience is going to be more and more important.

There is a great presentation over on dnrTV (Dot Net Rocks TV) where Mark Miller and Carl Franklin discuss the Science of Great User Experience. There are some really good nuggets in here that even as Powershell Scripters tweaking WPF, we can think about and use.

Also, if you are developer and use Visual Studio, you really should check out Dev Express’s CodeRush. This is the company that Mark works for and they really take User Experience for Visual Studio to the next level. It’s awesome.

Comments No Comments »

During the Scripting Games I found myself creating a lot of custom objects with properties that I could use to sort , select, take averages of, and a number of other cool things. Getting results into a Powershell object can make life a lot easier for a number of reasons.

There was one little piece I was missing. Not only did I want to create a single object, quite often I would want to put all the objects I created into a collection of objects. Did you know you can add collections of like objects to each other ?

   1: PS 13 >  $a = get-process

   2: PS 14 >  $a.count

   3: 66

   4: PS 15 >  $b = get-process

   5: PS 16 >  $c = $a + $b

   6: PS 17 >  $c.count

   7: 131

   8: PS 18 >

The code above shows that I can add two collections of process objects together. Very cool.

So I tried doing this in the scripting games and came across a problem. For instance, in Event 3 we needed to tally up a bunch of votes. So what I really needed was to create a bunch of $vote objects and put them all together in a collection called $votes

Here’s what I came up with at first.

By the way, when I create PS Custom Objects I cheat and use the “” | Select-Object prop1, prop2 nomenclature. My easier than using new-object followed by a bunch of add-member commands.

   1: $votes = "" | Select-Object v1,v2,v3,v4

   2: foreach ($v in Get-Content votes.txt)

   3:     {    

   4:         $vote = "" | Select-Object v1,v2,v3,v4;

   5:         $vote.v1,$vote.v2,$vote.v3,$vote.v4 = $v.split(",")

   6:         $votes += $vote

   7:     } 

Looks nice and shiny until you run it :) I get the following error:

Method invocation failed because [System.Management.Automation.PSObject] doesn’t contain a method named ‘op_Addition’.

Not so shiny

The trick is that we $votes needs to be a collection of $vote objects, not another object identical to $vote.

So we instantiate $votes with a cast to [array] and life is good.

   1: $votes = @()

   2: foreach ($v in Get-Content votes.txt)

   3:     {    

   4:         $vote = "" | Select-Object v1,v2,v3,v4;

   5:         $vote.v1,$vote.v2,$vote.v3,$vote.v4 = $v.split(",")

   6:         $votes = $votes + $vote

   7:     } 

A quick update, thanks to Aleksandar. We should instantiate $votes as $votes = @(). I have updated the example above.

Comments 3 Comments »

Event 5 in the Scripting Games dealt with testing whether or not a password is secure or not.  Among many qualifications, the password had to contain at least one digit, at least one upper case character and at least one lower case character. There also needed to be a check to see if the password contained any non-alphanumeric characters, such as $%^ or (.

All these could be dealt with using regular expressions, but regex skills are weak at best, so I always default to check and see if if someone has done it for me already. Sure enough, there are a bunch of static methods for System.Char that we can use.

   1: [char]::IsUpper()
   2: [char]::IsLower()
   3: [char]::IsDigit()
   4: [char]::IsLetterOrDigit()

From these we can build a filter that will pass the string if it meets the criteria. For the sake of example, lets build “Select-ContainsUpper”

   1: # Create a filter that can be used in a pipeline
   2: filter Select-ContainsUpper {
   3:     
   4:     # coerce the string into an array of chars and then pass each one to IsUpper
   5:     # IsUpper returns $TRUE or $FALSE for each char
   6:     # So ContainsUpper now contains an array of a bunch of Booleans
   7:     $containsUpper = $_.toCharArray() | % {[char]::IsUpper($_)}
   8:     
   9:     # if any char was uppercase, some element in ContainsUpper will be $TRUE
  10:     if ($containsUpper -contains $TRUE) {$_}
  11:     }
  12:     
  13: "one","Two","5","ContainsUpperCase","all-lower-case" | Select-ContainsUpper

Building Select-ContainsDigit and the others is left as an exercise to the reader.

You could also quite easily build a function that takes the string as a password, but lately I have been big on using filters and then putting them all together in a nice pipeline for the sake of clarity and a nice overall PowerShelly look.

Comments 1 Comment »

The gentlemen over at the Power Scripting Podcast recently posted a tip on how to start processes in Powershell.

I had run into the same problem they had. How do you pass in both an executable and its arguments to the Start method of a System.Diagnostics.Process object.

Something like this works fine in Powershell:

[System.Diagnostics.Process]::Start(“calc”)

But as soon as you try to pass in something like “ipconfig /all” the thing blows up.

Turns out you can pass in arguments a couple of ways. The Powerscripting guys noted that if you pass in the argument of the executable as a second argument to Start, it will work great.

[System.Diagnostics.Process]::Start(“ipconfig”,”all”)

However, there is another way if you want to get a little bit more fancy and do things like hide windows or redirect output from StdOut or StdErr.

You can use a System.Diagnostic.ProcessStartInfo object. Using get-member we can take a look at all the options we have for such a thing.

   1: PS 124 >  $si = New-Object System.Diagnostics.ProcessStartInfo
   2: PS 125 >  $si | gm  -type property | select Name
   3:  
   4: Name
   5: ----
   6: Arguments
   7: CreateNoWindow
   8: Domain
   9: EnvironmentVariables
  10: ErrorDialog
  11: ErrorDialogParentHandle
  12: FileName
  13: LoadUserProfile
  14: Password
  15: RedirectStandardError
  16: RedirectStandardInput
  17: RedirectStandardOutput
  18: StandardErrorEncoding
  19: StandardOutputEncoding
  20: UserName
  21: UseShellExecute
  22: Verb
  23: Verbs
  24: WindowStyle
  25: WorkingDirectory

Lots of goodness here that we can play with. Once you build up the ProcessStartInfo object, you pass that whole object in as the arg to the Start method of system.diagnostics.process.

I put together a quick function to show how this could be used more generically.

   1: function Start-Proc  {
   2:     param (
   3:             [string]$exe = $(Throw "An executable must be specified"),
   4:             [string]$arguments,
   5:             [switch]$hidden,
   6:             [switch]$waitforexit
   7:             )    
   8:     
   9:     # Build Startinfo and set options according to parameters
  10:     $startinfo = new-object System.Diagnostics.ProcessStartInfo 
  11:     $startinfo.FileName = $exe
  12:     $startinfo.Arguments = $arguments
  13:     if ($hidden){
  14:                 $startinfo.WindowStyle = "Hidden"
  15:                 $startinfo.CreateNoWindow = $TRUE
  16:                 }
  17:     $process = [System.Diagnostics.Process]::Start($startinfo)
  18:     if ($waitforexit) {$process.WaitForExit()}
  19:     
  20: }
  21:  
  22:  Start-Proc calc
  23:  Start-Proc calc -waitforexit
  24:  Start-Proc -exe ipconfig -arguments /all
  25:  Start-Proc ipconfig /all
  26:  Start-Proc ipconfig /all -hidden

I used the alias Start-Proc so that it would not collide with the PSCX Cmdlet Start-Process.

They have done the same writing their CmdLet  in C#, but with all kinds of options.

   1: PS 130 >  gcm Start-Process | fl *
   2:  
   3:  
   4: DLL              : C:\Program Files (x86)\PowerShell Community Extensions\Pscx.dll
   5: Verb             : Start
   6: Noun             : Process
   7: HelpFile         : Pscx.dll-Help.xml
   8: PSSnapIn         : Pscx
   9: ImplementingType : Pscx.Commands.StartProcessCommand
  10: ParameterSets    : {[[-Path] <String>] [[-Arguments] <String>] [-Verb <String>] [-WorkingDirectory <String>] [-Credential <PSCredential>] [-NoShellExecute] [-NoWindow]
  11:                    [-WindowStyle <ProcessWindowStyle>] [-LoadUserProfile] [-WaitTimeout <Int32>] [-Boost] [-Priority <ProcessPriorityClass>] [-Verbose] [-Debug] [-Error
  12:                    Action <ActionPreference>] [-ErrorVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] [-WhatIf] [-Confirm], [[-ScriptBlock] <ScriptBlock>
  13:                    ] [-NoProfile] [-WorkingDirectory <String>] [-Credential <PSCredential>] [-NoShellExecute] [-NoWindow] [-WindowStyle <ProcessWindowStyle>] [-LoadUser
  14:                    Profile] [-WaitTimeout <Int32>] [-Boost] [-Priority <ProcessPriorityClass>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-ErrorVariable <St
  15:                    ring>] [-OutVariable <String>] [-OutBuffer <Int32>] [-WhatIf] [-Confirm]}
  16: Definition       : Start-Process [[-Path] <String>] [[-Arguments] <String>] [-Verb <String>] [-WorkingDirectory <String>] [-Credential <PSCredential>] [-NoShellExecute]
  17:                     [-NoWindow] [-WindowStyle <ProcessWindowStyle>] [-LoadUserProfile] [-WaitTimeout <Int32>] [-Boost] [-Priority <ProcessPriorityClass>] [-Verbose] [-D
  18:                    ebug] [-ErrorAction <ActionPreference>] [-ErrorVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] [-WhatIf] [-Confirm]
  19:                    Start-Process [[-ScriptBlock] <ScriptBlock>] [-NoProfile] [-WorkingDirectory <String>] [-Credential <PSCredential>] [-NoShellExecute] [-NoWindow] [-W
  20:                    indowStyle <ProcessWindowStyle>] [-LoadUserProfile] [-WaitTimeout <Int32>] [-Boost] [-Priority <ProcessPriorityClass>] [-Verbose] [-Debug] [-ErrorAct
  21:                    ion <ActionPreference>] [-ErrorVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] [-WhatIf] [-Confirm]
  22:  
  23: Name             : Start-Process
  24: CommandType      : Cmdlet
  25: Visibility       : Public

Comments 5 Comments »