Using Session State Variables in a Module

I just had the opportunity to watch a great Pluralsight course called PowerShell Cmdlet Development in C# - The Ins and Outs.  One feature that Nathan went over was how to use session state in a Cmdlet.

Here is how session state can help you. His example was a Cmdlet called “Invoke-SQLQuery.” As you can imagine, this cmdlet would likely have several parameters, such as “Query”, “Server”, and “Database.” He had several more as well in his course but they are not relevant for this discussion.

As a user of this cmdlet, chances are you are going to be running queries against the same server and database multiple times. It is really annoying to have to type in  values for –server and –database all the time. As an end user of the cmdlet, one way to solve this is using PowerShell’s $PSDefaultParameterValues variable.  But as the author of the cmdlet, we can help the user out as well. In fact, we don’t even need to use C# to get this functionality in our own Script Cmdlets.

If you have written advanced functions, you have probably come across the [CmdletBinding] attribute that you can use to decorate your function. Most of the time, this is used to support “ShouldProcess” to give users the –confirm and –whatif options using the automatic variable PSCmdlet.

Well, it turns out there is a lot more available to us in the $PSCmdlet variable.   Just looking at intellisense, we can see a bunch of properties and methods in there.

image

Highlighted in the screenshot, you can see SessionState. If we continue to dig into this object, we find that it has a property called PSVariable, which is another object. There are several methods on this object that we can use to set and get values.

 

This allows us to set a value of a variable for as long as the session is available. When the session is gone, so is the variable and its value. We can write a bit of code so that once you use it the first time and specify the Server, you wouldn’t have to type it in the second time. I also threw in a Try / Catch to ensure that if there is no session state variable and the user doesn’t specify a server, than we let the user know that they need to specify the server parameter. We cannot use the “Mandatory” attribute on the [Parameter()] attribute because we would get prompted every time we want to use the cached session state variable.

TabExpansion++ Completers for AD Users and Groups

There is a lot of great documentation out there on using TabExpansion++.  If you haven’t started using it yet, I suggest you give it a whirl.

I wrote a couple quick Auto Completers that you can use as a starting point for AD Users and Groups.

Adding Aliases to your Functions with an Attribute

Function Test-Something {
[Alias("ts")]
[CmdletBinding(SupportsShouldProcess)]
param(
[Parameter(ValueFromPipeline)]
$What
)
Process {
        if ($pscmdlet.ShouldProcess($What)) {
        }
} # End Process
} # En

 

I picked this tip up on one of the videos from the PS Summit in Europe.  If I paste this into a PS session, I will get the alias automatically. #learnSomethingNewEveryDay

Seattle Script Club, October 2014 29th

Script Club - Wednesday, October 29th

 

The Seattle Script Club is a great way to get people up and running with PowerShell, and a great place to meet other PowerShell enthusiasts.  Club meetings are helpful for newbies, experts, and everything in between.  They're a wonderful way to learn new things about PowerShell and improve your scripting skills.  Oh, and there's free pizza too (courtesy of Edgile, Inc).

We hope to see many familiar faces at Script Club, and meet new scripters in the Seattle area.

The Seattle Script Club is coordinated by James Brundage from Start-Automating, Craig Martin from Edgile, and Andy Schneider from Avanade.

Location

Conference Room 18/1525

Microsoft Building 18, WA

http://binged.it/14Z4ahw

If you do not have building access, contact Craig to get escorted in (425-922-2760).

Agenda

4-6PM - Open Scripting Time

6-7PM - Feature Presentation - Cmdlet Design by James Brundage

7-?PM - Socialization

Open Scripting Time (4-5PM, Conf Room 18/1525)

                Bring in your troublesome scripts and get help fixing them.  Debug your problems with PowerShell experts.  Work on whatever you’d like.  Open Scripting Time will occur on Microsoft campus, and will rotate monthly to a Microsoft building close to a group in need.    Since Open Scripting Time will be on Microsoft campus, badge access or guest access will be required. 

PowerShell Presentation (6-7PM, Conf Room 18/1525)

                Each month, we’ll be doing a 1-hour presentation on a topic of interest to Seattle area scripters.  This club presentation is on PowerShell Cmdlet design.  Each presentation will be followed by extensive Q&A and interesting show and tell by other members of the group.

Socialization (7-?PM, Some Place Nearby TBD):

                After your brains have been thoroughly stuffed with PowerShell knowledge, clear your head and chat with your fellow scripters.  Each month we’ll be hanging out after Script Club and enjoying the company of our fellow scripters.  The first round for new attendees to Script Club is on Start-Automating.

Get-NextBusinessDay

I had a need to calculate the next business day in a script I was writing.

Pretty short and sweet.

 

Function Get-NextBusinesDay {
param($days)
$date = get-date
$newDate = $date.AddDays($days)
switch ($newDate.DayOfWeek)
    {
       "Saturday" {$newDate = $newDate.AddDays(2); $newDate}
       "Sunday"   {$newDate = $newDate.AddDays(1); $newDate}
       Default {$newDate}
    }
}

 

image

Seattle Script Club is Back!

James Brundage, Craig Martin, and I are happy to announce that after several years of hiatus, the Seattle Script Club is starting once again.

Script Clubs have been a great way to get people up and running with PowerShell, and a great place to meet other PowerShell enthusiasts.  They’re helpful for PowerShell newcomers, experts, and everything in between.  They’re a wonderful way to learn new things about PowerShell and improve your scripting skills.

The first new Seattle Script club is this Wednesday, September 24th, 2014.   They’ll happen every 4th Wednesday of a month.  The main event will happen in the Civica conference room at the Microsoft offices at 205 108th Ave NE, Bellevue, WA.   Social time will be in Bellevue, at a bar of the group’s choosing.  The first round for newcomers is on Start-Automating.

Here’s what the Seattle Script Club will have in store for you:

PowerShell Presentation (6:00PM-7:30 PM, Civica Conference Room, Microsoft Bellevue Offices (205 108th Ave NE)):

                Each month, we’ll be doing a 1-hour presentation on a topic of interest to Seattle area scripters.  The first month will be on SQL and PowerShell (It’s got some cool scripts in it, don’t miss it!).  The second month will be on PowerShell Cmdlet design.  The third month will be on intranet development with PowerShell.   Each presentation will be followed by extensive Q&A and interesting show and tell by other members of the group.

Socialization (8:00 - ?, Downtown Bellevue):

                After your brains have been thoroughly stuffed with PowerShell knowledge, clear your head and chat with your fellow scripters.  Each month we’ll be hanging out after Script Club and enjoying the company of our fellow scripters.  The first round for new attendees to Script Club is on Start-Automating.

We hope to see many familiar faces at Script Club, and meet new scripters in the Seattle area.

The Seattle Script Club is coordinated by James Brundage from Start-Automating, Craig Martin from Edgile, and Andy Schneider from Avanade

ADAL and PowerShell

ADAL v2 was just released. This is a library that makes it super easy to auth against Azure AD in an application.  Here’s a link to a very quick demo. http://www.cloudidentity.com/blog/2014/09/08/getting-started-with-adal-for-netquick-video-tutorial/

Well, if it can be done in WPF, surely we can do this in PowerShell. The first thing you have to do is make sure you have the Nuget command line tool installed.

Then you just run this command -

nuget install Microsoft.IdentityModel.Clients.ActiveDirectory

 

After that, you can find the 2 dll’s you need in the Microsoft.IdentityModel.Clients.ActiveDirectory.2.9.10826.1824\lib\net45 directory.

Now comes the fun part.

 

Add-Type -Path .\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll 
Add-Type -Path .\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll 
$tenant = "yourdomainhere.onmicrosoft.com" 
$resource = "https://graph.windows.net" 
$clientID = "dfbf167a-add-your-own-clientid-here" 
$redirect = new-object System.Uri("http://powershell") #as long as this is unique in your tenant, all good 
$AuthContext = new-object Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext("https://login.windows.net/$tenant") 
$result = $AuthContext.AcquireToken($resource,$clientID,$redirect) 
$result

Why teach your kid times tables when you can teach them times tables and a little bit of coding ?

So I promised my daughter a big present if she could learn all of her times tables, up to 12 x 12. Sure, we have some flash cards, and there are endless apps on any software platform to practice math facts. But why do that when you can write your own? The side benefit, is that she and I can personalize it to whatever we want. Next up is division, but she is going to have to help me code up that functionality.

 

image

 

image

 

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace PracticeMultiplication
{
    class Program
    {
        static void Main(string[] args)
        {
            // Get the largest number to multiply by, up to 12
            // Choosing 2 will get 1 x 12 - 2 x 12, choosing 6 will get 1 x 12 up through 6 X 12
            Console.Write("What's the largest number you want to multiply (1-12) ? ");
            int max = Convert.ToInt32(Console.ReadLine());
            Console.WriteLine("Just type 'done' or 'q' to quit");
            string studentAnswer = String.Empty;
            int score = 0; //total correct answers
            int correctAnswersInARow = 0; // correct answers in a row
            while (true)
            {
                ShowCurrentScore(score, correctAnswersInARow);
                // Generate a new problem using random numbers based on the max value
                // num2 will always be between 1 and 12
                Random random = new Random();
                int num1 = random.Next(0, max);
                int num2 = random.Next(0, 12);
                Console.Write("{0} x {1} = ", num1, num2);
                studentAnswer = Console.ReadLine();
                // check to see if we should quit
                if (studentAnswer == "done" || studentAnswer == "q")
                { 
                    break; 
                }
               // Convert to Int so we can multiply and see what the answer is
                int studentNumber = Convert.ToInt32(studentAnswer);
                int answer = (num1 * num2);
                if (answer == studentNumber)
                {
                    // Score and Correct get bumped up if they get it right.
                    score++;
                    correctAnswersInARow++;
                    // If they get 5 rigth in a row, they get a bonus of 5 points
                   // Using Modulo 5 to test for divisible by 5
                    if (correctAnswersInARow > 1 && correctAnswersInARow % 5 == 0)
                    {
                        score += 5;
                        WriteMessage("Bonus 5 points for getting 5 right in a row!", ConsoleColor.DarkGreen, score);
                    }
                    WriteMessage("Great Job Madeline! ",ConsoleColor.Green,score);
                }
                else
                {
                    WriteMessage("Oh bummer! Let's try another one",ConsoleColor.Red,score);
                    // reset to 0 since we got it wrong
                    correctAnswersInARow = 0;
                }
            }
        }
        private static void ShowCurrentScore(int score, int rightInarow)
        {
            Console.BackgroundColor = ConsoleColor.Blue;
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.WriteLine("Your score is {0}                        ", score);
            Console.WriteLine("You have got {0} correct answers in a row", rightInarow);
            Console.WriteLine();
            Console.ResetColor();
        }
        private static void WriteMessage(string Message, ConsoleColor Color, int score)
        {
            Console.ForegroundColor = Color;
            Console.WriteLine(Message);
            Console.WriteLine("Your score is {0}",score);
            Thread.Sleep(1000);
            Console.ResetColor();
            Console.Clear();
        }
    }
}

Active Directory Search that works - Ambiguous Name Resolution

I am not a big fan of having to specify filters using the syntax prescribed for Get-ADuser.  Ambiguous Name Resolution is an old API that allows you to query against multiple attributes at the same time. There is some more information on ANR here http://support.microsoft.com/kb/243299

By default, the following attributes are set for ANR:

  • GivenName
  • Surname
  • displayName
  • LegacyExchangeDN
  • msExchMailNickname
  • RDN
  • physicalDeliveryOfficeName
  • proxyAddress
  • sAMAccountName

It turns out you just need to pass in an LDAP Query. Once you get the list of results, you can pipe them into the Get-ADuser cmdlet to get the user objects as you would expect them. All we have to do is build an LDAP Filter and query against an attribute called ANR. This will return all objects that have an attribute from the list above that maches User. You can kind of think of it as a wildcard search on steroids.

Function Get-User {
param(
[Parameter(ValueFromPipeline)]
$User
)
BEGIN {import-module activedirectory}
PROCESS {
   $filter = "(&(ObjectClass=User)(ANR=$User))" 
   Get-ADObject -LDAPFilter $filter  |
   Get-ADUser
}
}

Hope this is helpful.

FIM and Orphaned Expected Rule Entries (ERE’s)

I just started working with FIM 2010 R2 in a development environment. Before you read any further, please take this into consideration. All of this has come from a development environment. I would never do this in a production environment. I would probably go as far as to say that my level of fear and caution for “Hey, what does this button do?” type of scenarios is probably a little too low.

With that understanding, let’s get to the point. I was setting up a typical scenario with a SQL MA and and Active Directory MA. The SQL Database has approximately 50,000 entries that I needed to pull into the metaverse. I like to learn by doing. Yeah, I read a little bit before I started, but clearly not enough. I was still trying to figure out if I was going to use classic rules or if I was going to need to use the FIM portal to create Synchronization rules. After several imports, exports, and syncs, and then messing with Sync rules, I finally decided that I actually did need to use the FIM portal and Synchronization rules. I wanted to start with a completely clean slate. So I went in and deleted everything, including MA’s.

The problem came up when I deleted the FIM service Management Agent connector space. No matter what I did, every time I did an import, it would pull in about 150,000 Expected Rule Entries, or ERE’s.

Poking around in the FIM Script Box, I found some PowerShell code that could delete these for me. Basically, it does a search for all the orphaned ERE’s using the FIM web service under the hood of the “Export-FIMConfig” PowerShell cmdlet. Well this is great if you are looking at a couple 100 objects. But with 150,000 objects, I was looking at more like days.

So I decided to poking around a bit more. I figured that at the end of the day, these objects have to be somewhere in the database. If you are getting worried now, don’t. I promise it gets better. Looking at the FIMService database, I found one table that was particularly interesting. There is a FIM.objects table. Sweet!

image

Here’s where it got a little nuts. Looking in the connector space, I found the object ID of ONE of my orphaned ERE’s. It had an objectID of something like “B8A72DEB-6A7F-482F-81A6-8DD66D91D6EA.”

So I ran a quick query like the following

SELECT * FROM Fim.Objects
WHERE ObjectID = 'B8A72DEB-6A7F-482F-81A6-8DD66D91D6EA'

Here I found out that it had an ObjectType of 11. Looking at the table, it was referencing the ObjectTypeInternal table.

image

So the next thing I did was run a similar query and found “Astonishingly!” that there were about 150,000 ERE objects with ObjectType = 11.

Using this query, I was able to find all the ObjectKey’s of all the objects I needed to delete.

SELECT * FROM Fim.Objects
WHERE ObjectTypeKey = 11

Now I needed a way to delete these suckers. Looking over the database, I was wondering if there might be some stored procedure I might be able to use.

Low and Behold, sitting there, was something called debug.DeleteObject

image

Nevermind the “Debug” prefix on this stored procedure. Using a little Excel Magic, I created a huge long SQL command (What can I say, I am not a SQL guy) that looked something like this. I basically took the ObjectKey column from the last query, dumped it in excel, and then used some string manipulation to generate my SQL script.

image

 

Here’s what eventually what went into SQL Query Analyzer – actual code was 150,000 calls.

image

Running this only took about a little over 2 hours. Way faster than using the Import-FimConfig and Export-FIMConfig. Using the web service abstraction layer is great and all, but sometimes you just need to bypass as much as possible.

So the next time you are working in a development environment and feel like taking a chance on blowing off your toe, or maybe your whole foot, this just might help!