Wednesday, November 25, 2009

In this post I will show you a very simple example of how advanced functions in PowerShell 2.0 can be used to declared your own cmdlets. If you want to run these script samples you will need to run PowerShell as an Administrator when executing set-name and join-workgroup.

Joining a workgroup:

$sysInfo = Get-WmiObject -Class Win32_ComputerSystem
$sysInfo.JoinDomainOrWorkgroup( "Bradley" )

Changing the computer name

Another useful example is changing the name of the computer, to do this issue the following command, but remember you must execute this command while in a PowerShell session that has Administrative privileges and you will be required to reboot the computer before these changes take effect (Restart-Computer can do this for you):

$sysInfo = Get-WmiObject -Class Win32_ComputerSystem
$sysInfo.Rename("FORSETI")

For completeness and fun I'll now show you how you can take these simple lines of script and create your own cmdlets so that you will have the cmdlets Get-ComputerName, Set-ComputerName, Get-Workgroup and Join-Workgroup at your disposal.

Get-ComputerName

This cmdlet just returns the value held in the environment variable COMPUTERNAME, I'm providing this cmdlet just to have consistency in getting and setting the name of a computer. If you wish to run this script on PowerShell 1.0 simply remove the block comment, this has been included to illustrate how you may document you cmdlets.

function Get-ComputerName
{
    <#
    .SYNOPSIS
        Gets the name of the computer
    .DESCRIPTION
        Returns a string containing the name of the computer
    .NOTES
        File Name: ComputerName.psm1
        Aurthor: Alan Bradley
        Requires: PowerShell 2.0
    .LINK
        http://www.gangleri.net
    .EXAMPLE
        Get-ComputerName
        
    #>
    process 
    {
        $Env:COMPUTERNAME
    }
}

Set-ComputerName

Not much more complicated than the Get-ComputerName cmdlet but this one accepts a parameter that will be the new name of the computer, if ts successfully changes the name of the computer it will prompt the user to reboot the machine so that the change can be applied. I have provided a switch parameter called 'AutoReboot' that when provided will automatically reboot the machine when the name has successfully been changed.

function Set-ComputerName
{
    <#
    .SYNOPSIS
        Sets the name of the computer
    .DESCRIPTION
        Uses WMI to set the name of the computer, if the name is successfully changed the user will be prompted to reboot and apply the changes
    .NOTES
        File Name: ComputerName.psm1
        Aurthor: Alan Bradley
        Requires: PowerShell 2.0
    .LINK
        http://www.gangleri.net
    .EXAMPLE
        Set-ComputerName -Name "{New name for computer}"
    .EXAMPLE
        Set-ComputerName "{New name for computer}"
    .EXAMPLE
        Set-ComputerName -Name "{New name for computer}" -AutoReboot
    .EXAMPLE
        Set-ComputerName "{New name for computer}" -AutoReboot
    .PARAMETER Name
        The new name that the computer will be known by
    #>
    param(
        [Parameter(Position=0, Mandatory=$true,ParameterSetName="Name")]
        [string]$Name,
        
        [Switch]$AutoReboot
    )
    
    process 
    {
        $sysInfo = Get-WmiObject -Class Win32_ComputerSystem
        $result = $sysInfo.Rename($Name)
    
        switch($result.ReturnValue)
        {        
            0 
            { 
                Write-Host -ForegroundColor Green "Success"
                
                if($AutoReboot -eq $false)
                {                    
                    $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", `
                        "Reboots the machine."
                        
                    $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", `
                        "Does not reboot the machine, you will manually have to reboot this machine for changes to take effect."
                        
                    $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)    
    
                    
                    $ShouldReboot = $Host.UI.PromptForChoice("Reboot machine", `
                        "You must reboot for change to take effect. Do you want to reboot now?", $options, 0)
                }
                
                if($ShouldReboot -eq 0 -or $AutoReboot -eq $true)
                {
                    Restart-Computer
                }
            }
            5 { Write-Host -ForegroundColor Red "This cmdlet must be execute with administrative privileges" }            
            default { Write-Host -ForegroundColor Red "Error" }
        }
        
    }
}

Get-Workgroup

Similarly cmdlets can be created for changing the workgroup and domain settings. Here is the cmdlet that can be used to get the workgroup name. Again this can be adapted for PowerShell 1.0 by removing the block comments.

function Get-Workgroup
{
    <#
    .SYNOPSIS
        Get the Workgroup name that the computer currently belongs to
    .DESCRIPTION
        This cmdlet returns the name of the Workgroup that the computer
        currently belongs to.
    .LINK
        http://www.gangleri.net
    .Example
        Get-Workgroup
    #>
    process
    {
        (Get-WmiObject -Class Win32_ComputerSystem).Workgroup
    }    
}

Join-Workgroup

Joining a Workgroup can be achieved with the following cmdlet. This cmdlet uses some of the new advanced binding abilities added to PowerShell 2.0 for parameters.

function Join-Workgroup
{
    <#
    .SYNOPSIS
        Joins the specified Windows work group
    .DESCRIPTION
        This cmdlet allows you to specify the name of a Windows Workgroup
        that you would like to join the computer to. You will need to reboot
        for these changes to take effect so the cmdlet will prompt you to do
        this, alternatively you can use the -AutoReboot switch as this will
        automatically reboot the machine so that the changes are applied.
    .LINK
        http://www.gangleri.net
    .Example
        Join-Workgroup "WorkgroupName"
    .Example
        Join-Workgroup "WorkgroupName" -AutoReboot
    .EXAMPLE
        Join-Workgroup -Workgroup "WorkgroupName"
    .EXAMPLE
        Join-Workgroup -Workgroup "WorkgroupName" -AutoReboot
    .PARAMETER Workgroup
        The name of the Windows Workgroup you wish to join
    .PARAMETER AutoReboot
        If supplied this instructs the cmdlet to automatically 
        reboot the computer so that the changes can take effect
    #>
    
    param(
        [Parameter(Position=0, Mandatory=$true,ParameterSetName="Workgroup")]
        [string]$Workgroup,
        
        [Switch]$AutoReboot
    )

    process
    {
        $sysInfo = Get-WmiObject -Class Win32_ComputerSystem
        $result =  $sysInfo.JoinDomainOrWorkgroup( $Workgroup )
        
        switch($result.ReturnValue)
        {            
            0 
            { 
                Write-Host -ForegroundColor Green "Success"
                
                if($AutoReboot -eq $false)
                {                    
                    $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", `
                        "Reboots the machine."
                        
                    $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", `
                        "Does not reboot the machine, you will manually have to reboot this machine for changes to take effect."
                        
                    $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no)    
    
                    
                    $ShouldReboot = $Host.UI.PromptForChoice("Reboot machine", `
                        "You must reboot for change to take effect. Do you want to reboot now?", $options, 0)
                }
                
                if($ShouldReboot -eq 0 -or $AutoReboot -eq $true)
                {
                    Restart-Computer
                }
            }
            
            5 { Write-Host -ForegroundColor Red "This cmdlet must be execute with administrative privileges" }
            
            default { Write-Host -ForegroundColor Red "Error" }
        }
    }
}

Changing the Domain

Working with domains is similar to working with workgroups, you will use the JoinDomainOrWorkgroup method only you need to specify additional arguments for the user name and password. The values one and two are important. One means join the domain and two means create the account.

$sysInfo = Get-WmiObject -Class Win32_ComputerSystem
$sysInfo.JoinDomainOrWorkgroup( "Bradley", "password", "Bradley\Admin", 1, 2 )

If you fancy a small challenge you could try writing your own cmdlet 'Join-Domain' give me a shout if you need any help. Also how the return codes are processed could be wrapped up in a function I've just duplicated code here to make it easy for people to copy/paste these examples and play with them. I'll be posting a sort example of turning these scripts into PowerShell 2.0 modules that you can easily distribute to others.

Although the add-computer cmdlet in PowerShell 2.0 can achieve this same functionality I still think these are good examples of developing your own cmdlets using PowerShell 2.0 advanced functions as they are not complicated and allow you to focus on the nuts and bolts of advanced functions. Next I'll walk you through packaging these as modules so that you will then be in a position to easily redistribute your cmdlets to others.

posted on Wednesday, November 25, 2009 11:48:12 PM (GMT Standard Time, UTC+00:00)  #    Add Comment | Comments [0]
 Monday, November 16, 2009

wireless-extender At home I have a Playstation 3, Xbox 360, three laptops and a desktop computer all looking to share Internet access and so far it's all been a piece of cake thanks to the dLan high-speed Ethernet plugs from Devolo. These have been a dream and scaled really well as new kit has been added to the home network, it was just a matter of simply plugging an Ethernet cable into the device and one of these plugs into the wall socket. Although when I'm writing code I tend to be reasonably disciplined in wirelessExtenderDiagramlocking myself away if I'm just browsing the web or reading blogs I'd like to have the freedom to go where ever I want. The only problem with this has been the limited range of the BT home hub. But I've just found the perfect solution Devolo have a wireless extender so all I have to do is plug this in wherever I want and I now I always have a really strong Wi-Fi connection if I'm just sitting in the living room surfing and watching TV. Again this was really easy to setup as it worked straight out of the box with my existing home network and I'd recommend anyone in a similar situation give this a try. 

posted on Monday, November 16, 2009 11:24:56 PM (GMT Standard Time, UTC+00:00)  #    Add Comment | Comments [0]
 Thursday, November 05, 2009

I've had a few questions regarding uninstalling Windows PowerShell 1.0 on XP to make way for PowerShell 20. It's actually quiet simple although not immediately obvious. PowerShell doesn't show up under Add/Remove programs as it's counted as a Windows update so follow these steps it you want to uninstall it.

    1. Click Start -> Run
    2. Type appwiz.cpl and press enter
    3. Windows PowerShell will not show up in the list of programs as it is counted as a windows update, you must click the tick box "Show updates"
    4. Scroll down and look for "Windows XP - Software Updates"
    5. Underneath the Windows XP -Software updates entry is a list of all updates that have been applied to you machine scroll through the list and you will find an entry call "Windows PowerShell(TM) 1.0"
    6. Click the "Remove" button to begin uninstalling PowerShell 1.0

 Screen showing Add Remove PowerShell

 

You can find more details on this in the Microsoft knowledgebase at:  http://support.microsoft.com/kb/926139

posted on Thursday, November 05, 2009 8:33:13 PM (GMT Standard Time, UTC+00:00)  #    Add Comment | Comments [2]
 Wednesday, November 04, 2009

Getting a string value for an enum value is a common problem and there's a few solutions knocking around the Internet, however a few of these that I've seen end up having a utility class that handles mapping the enum value to the relevant string value, this is fine but I think this is an operation that should be callable on the enum value without having to go off and use another class. The solution I have here provides this functionality using extension methods that are available in .Net 3.5.

The first thing I did was to create a new attribute that will be applied to the enum values when they are declared so a string value can be specified for each enum value such as is shown in the code snippet below:

 

public enum 
{
    [StringValue("Red")]
    Red = 0,
    [StringValue("Blue")]
    Blue = 1,
    [StringValue("Green")]
    Green = 2
} 


The code for the attribute class is:

public class StringValueAttribute : Attribute 
{ 
    public string StringValue { get; private set; }

    public StringValueAttribute(string value) 
    { 
         this.StringValue = value; 
     } 
}

When writing the extension method we can take advantage of the fact that all enums have Enum as their base class. This allows the following extension to be defined.

public static stringGetStringValue(this Enum enumValue) 
{ 
   . . . 
}

This method is now available to be called as follows: 

Colors myColor = Colors.Red; 
Console.WriteLine(myColor.GetStringValue());

 

As the 'GetStringValue' extension method is available on all enums it leaves the possibility that GetStringValue could be called on enums that have not used the 'StringValue' attribute. To protect against this there are two options, option one would be to return an empty string and option two is to use reflection and return the name of the enum value. This was the option I choose, firstly I look for the 'StringValue' attribute if that is present the method returns that as this is the mechanism that allows the developer to take finer control of the string value. So the previous enum could be defined as follows:

 

public enum Colors 
{ 
        [StringValue("#FF0000")] 
        Red = 0, 

        [StringValue("#0000FF")] 
        Blue = 1, 

        [StringValue("#00FF00")] 
        Green = 2 
}

Likewise the enum could be defined as shown below and we would get the values 'Red', 'Green' and 'Blue' when using the 'GetStringValue' method.

public enum Colors 
{ 
        Red = 0, 
        Blue = 1, 
        Green = 2 
}

Here is my implementation of the extension method: 

public static string GetStringValue(this Enum enumValue) 
{ 
    Typetype = enumValue.GetType(); 
    FieldInfo fieldInfo = type.GetField(enumValue.ToString()); 

    StringValueAttribute[] attribs = fieldInfo.GetCustomAttributes( 
        typeof(StringValueAttribute), false) as StringValueAttribute[]; 

    if(attribs.Length > 0) 
    { 
        return attribs[0].StringValue; 
    } 
    else 
    { 
        return fieldInfo.Name;  
     }  
}


I've a prebuilt DLL so all you need to do is download this and reference it in your projects making sure to include the namespace 'Gangleri.Enums' when you wish to use the extension method or the StringValue attribute.

DLL: http://enumstringvalue.googlecode.com/files/Gangleri.Enums.dll.zip
Source Code: http://code.google.com/p/enumstringvalue/source/checkout

posted on Wednesday, November 04, 2009 9:13:16 PM (GMT Standard Time, UTC+00:00)  #    Add Comment | Comments [1]

If you've got an account that uses Google mail you have got to try out the Gmail Notifier Plus app as it looks so good on Windows 7. Just look at the Jump Menu for the app. At a glance you can see how many new items are in your inbox and gmailNotifierPlusJumpMenu most recent 10 have their subjects listed on the Jump menu so that you can go directly to any of them with a single click. Also from the tasks section you have the option to compose a new mail or go to your inbox, both of these options will open a browser with the selected page displayed.

Another very nice feature of the app occurs when you mouse over the icon on the Windows 7 task bar. You get a small preview window that allows you to step through your mail and read the first few lines from each and for convenience you have the ability to open the full email in your browser.gmailNotifierPlusMouseOver Trust me if you have a Google mail account you want to check this little app out as it makes it so easy to work with your gmail.

posted on Wednesday, November 04, 2009 1:52:55 AM (GMT Standard Time, UTC+00:00)  #    Add Comment | Comments [1]