DCSIMG
Shay Levy

Shay Levy

If you repeat it, PowerShell it!

News


btn_donate_LG

View Shay Levy's profile on LinkedIn Follow Shay Levy at Twitter Shay Levy's Facebook profile Subscribe to my FriendFeed


site statistics




New advanced functions language features in PowerShell v3

PowerShell 3.0 CTP1 includes many new language enhancements. Here are four of them for advanced functions.

 

CmdletBinding and Parameter attributes

We are no longer required to assign a value of $true to CmdletBinding and Parameter attributes. For example, in v2 we had to write:

 

[CmdletBinding(SupportsShouldProcess=$true)]            
param(            
    [Parameter(Position=0,            
        ValueFromPipeline=$true,            
        ValueFromPipelineByPropertyName=$true            
    )]            
    [string]$Name            
)
In v3 we can omit the assignment.
            
[CmdletBinding(SupportsShouldProcess)]            
param(            
    [Parameter(Position=0,            
        ValueFromPipeline,            
        ValueFromPipelineByPropertyName            
    )]            
    [string]$Name            
)            
            

The absence of an attribute is same as explicitly setting the attribute to $false, but that isn’t new to v3, is the same as v2.

 

Built-in support for Paging operations

[CmdletBinding(SupportsPaging)]

When the SupportsPaging attribute of CmdletBinding is specified in advanced functions we get three additional parameters IncludeTotalCount,Skip, and First. These parameters allows us to page the results. When the IncludeTotalCount is specified the function writes to the host the total amount of objects in the form of:

Total count: n

 

The Skip parameter, UInt64, controls how many objects the function ignores. The value cannot be greater than the total amount of objects in the result. The First parameter, UInt64, controls how many objects the function returns from the beginning of the result.

You can find a script example in the samples folder of CTP1 (Samples\WindowsPowerShell\SupportsPagingSample\SupportsPaging01.ps1).

 

HelpUri

Assign it a web URL and Get-Help will pick it up when the Online switch has been specified, and will
display the page in your default browser. Get-Command also shows the URI in its result.

[CmdletBinding(SupportsPaging,HelpUri='http://PowerShay.com')]             
 

PositionalBinding

[CmdletBinding(PositionalBinding=$false)]             

Setting PositionalBinding to $false allows us to disable positional parameters binding and force users to write the parameter name and its value. See this post for more information.

Windows PowerShell 3.0 CTP1 is available for download!

Windows_PowerShell_iconWindows Management Framework 3.0 Community Technology Preview (CTP1) is available for download for Windows 7 SP1 and Windows Server 2008 R2 SP1.

Read the full announcement on the PowerShell team blog. Check out this post on the PowerShell Magazine site for a quick review of new cmdlets and parameters in v3.

How to disable positional parameter binding in PowerShell vNext

Windows PowerShell supports two kind of parameters: Named and Positional. In a nutshell, Named parameters must be specified on the command line while Positional parameters are inferred by the argument’s position on the command line.
The type of the parameter is controlled by the [Parameter()] attribute (see about_Parameters).

What if we wanted to disable positional parameters and force users to write the parameter name and its value?
Consider the following example, all parameters values are positional. Can you guess the parameter names?

PS> Register-ObjectEvent $timer Elapsed Timer.Random {$random = Get-Random -Min 0 -Max 100}


There is some logic in the order of values but that is a bit hard to read and involves some guess work as well as consulting the help files. It is also not recommended when writing production scripts and can cause a lot of frustration for users who are not familiar with the command.

In PowerShell v2 it was not possible to disable that behavior (see a work around at the end of this post).
By default, values on the command line where treated as positionals, but in PowerShell v3 the PowerShell team added a new
functionality to address it.

The CmdletBinding attribute is used in Advanced functions to identify them as functions that act similar to compiled cmdlets.
When we write advanced functions, we can add the CmdletBinding attribute so that Windows PowerShell will bind the parameters of the function in the same way that it binds the parameters of compiled cmdlets. Some of the known arguments of the CmdletBinding attribute are: SupportsShouldProcess, DefaultParameterSetName and ConfirmImpact.
You can read more about them in the about_Functions_CmdletBindingAttribute help topic.

In PowerShell v3 we have additional CmdletBinding attribute - PositionalBinding (there are more new attributes!).
As its name suggests, when specified it disables positional binding and force the caller to specify parameter names.
Let's test it with the following function.


function Test-PositionalBinding             
{             
    [CmdletBinding(PositionalBinding=$false)]             
            
    param(             
       $param1,$param2             
    )             
            
    Write-Host param1 is: $param1            
    Write-Host param2 is: $param2             
}             

 


As you can see, the PositionalBinding attribute is set to $false. The function will not allow positional binding.

PS> Test-PositionalBinding -param1 one -param2 two

param1 is: one
param2 is: two


In the example above we specified parameter names and the result is as expected. Let's try to pass the value of param1 by its position.


PS> Test-PositionalBinding one -param2 two

Test-PositionalBinding : A positional parameter cannot be found that accepts argument 'one'.
At line:1 char:1
+ Test-PositionalBinding one -param2 two
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Test-PositionalBinding], ParameterBindingException
    + FullyQualifiedErrorId : PositionalParameterNotFound,Test-PositionalBinding


And it fails. Check this forum thread if you need to enable similar functionality in PowerShell v2, great workaround by @mjolinor.

Want to try PowerShell v3? Download the Windows 8 Developer Preview from MSDN.

Get Your Game On! Leverage Proxy Functions In Windows PowerShell

TECI’m excited to announce that MVP Kirk Munro (aka poshoholic) and I are going to present in the upcoming PowerShell Deep Dive track at the The Experts Conference in Frankfurt, Germany (17-19 October 2011).

 

In this session we will take a deep dive into proxy functions in PowerShell. We have been working together on PowerShell Proxy Extensions, a powerful module that leverages proxy functions and makes it easier than ever to create these powerful extensions to PowerShell. We will demonstrate what proxy functions are and why they are important, and then show how a little scripting savvy (and a really long script) can make your life easier by allowing you to create everything from very simple proxy functions that extend PowerShell to more complex proxy functions that override existing commands, fixing bugs and adding missing features at the same time, all while leveraging inline help as much as possible.

This session will arm you with the knowledge (and tools!) you need to be able to get the most from proxy functions today!

Looking forward to see you there!

PowerShell Seminar - Microsoft Infra Days 2011 (Hebrew)

מקווה לראותכם בכנס. מהרו להירשם (לחצו על התמונה), מספר המקומות מוגבל!

InfraDays2011

Get Full Control over your Exchange remote PowerShell session

PowerShell 2.0 supports two kinds of remote configurations: fan-in and fan-out. When we execute a command against a bunch of servers we use fan-out (one to many). Fan-in is used when multiple users are connecting to a remote server (many to one). Exchange server implements a fan-in configuration via a virtual directory on the Exchange server’s IIS. We can connect to the virtual directory (http connection) and manage our Exchange server remotely, without having to install the Exchange Management Tools locally on our admin station.

We can create a remote session (using the currently logged on credentials) with the New-PSSession cmdlet. If you need to connect with alternate credentials, add the –Credential parameter:

PS > $uri = 'http://dc1.homelab.com/PowerShell' 
PS > $session = New-PSSession -ConfigurationName Microsoft.Exchange `
-ConnectionUri $uri -Authentication Kerberos

The session is created and we can import the commands from the remote session into our local session and use them as if they were installed locally (aka, implicit remoting).

PS> Import-PSSession –Session $session


When the session finished importing, all commands from the remote session are available in our local session. In the background a module is created that contains all remote commands. Let’s try one command:

PS > Get-MailboxDatabase

Name                           Server   Recovery  ReplicationType
----                           ------   --------  ---------------
Mailbox Database 0311695863    DC1      False     None

Now let’s try to get the database size:

PS > $db = Get-MailboxDatabase -Identity 'Mailbox Database 0311695863' -Status
PS > $db.DatabaseSize
152.1 MB (159,449,088 bytes)

 

We get back the size of the database in MB and in bytes. Exchange supports several methods to format the size of an object (mailbox/database) through a series of methods: ToBytes(), ToKB(), ToMB() etc. Let’s try to format the size of the database and get the value in bytes:

PS > $db.DatabaseSize.ToBytes()
Method invocation failed because [System.String] doesn't contain a method named 'ToBytes'.
At line:1 char:25
+ $db.DatabaseSize.ToBytes <<<< ()
    + CategoryInfo          : InvalidOperation: (ToBytes:String) [], RuntimeException
    + FullyQualifiedErrorId : MethodNotFound

 

We get an error that the DatabaseSize property doesn't contain the ToBytes method. We can also see that DatabaseSize is a String. This is the expected behavior in a remoting session. When a source computer sends a script to a remote computer, the code is serialized first (converted to XML), when it gets to the destination machine it's converted back (deserialized) and executed. The result is serialized again and sent back to the source computer. It is important to understand that when the source computer gets the final result, it convert it back to objects but the objects are "dehydrated", and contains a bunch of Note properties and one method - ToString (some "primitive" types, like Int, can be deserialized better than others). As a consequence, if we want to execute methods on the "real" object we need to do that on the remote end. When we want to get hold of the object itself (and it’s members) we invoke the command on the remote end with the Invoke-Command cmdlet:

PS > $identity = 'Mailbox Database 0311695863'
PS > $sb = {(Get-MailboxDatabase -Status –Identity $identity).DatabaseSize.ToBytes()} PS > Invoke-Command -Session $session -ScriptBlock $sb Method calls are not allowed in restricted language mode or a Data section. + CategoryInfo : ParserError: (ToGB:Token) [], ParseException + FullyQualifiedErrorId : MethodCallNotSupportedInDataSection

 

Another error! We cannot run methods in restricted language mode. What does this mean? The Exchange configuration is locked down (restricted session). By default, only administrators can connect to the end point, but they are restricted as well!

A few words on the LanguageMode property. There are three possible values: NoLanguage, RestrictedLanguage, and FullLanguage. In FullLanguage you can do whatever you want. In NoLanguage mode only commands that are using the Runspace APIs are allowed, and in RestrictedLanguage mode commands that contain scripts that need to be evaluated are not allowed.

This was a bit disappointing. If the server admin cannot have full access to the remote session then who can? I’m not sure why the Exchange team decided to lock the environment. The notion of connecting to any remote server and managing it without having to install local tools is not fulfilled here.

I started to look for a way to bypass that limitation and it appears that I was looking in the wrong direction! Hats off to my friend, MVP Aleksandar Nikolic, for a great tip! We can change the language mode by opening the web.config file in the PowerShell virtual directory:

image_thumb image_thumb3

 

I changed the value to FullLanguage, saved the file, recycled the MSExchangePowerShellAppPool application pool and re-created a remote session:

PS > $uri = 'http://dc1.homelab.com/PowerShell' 
PS > $session = New-PSSession -ConfigurationName Microsoft.Exchange `
-ConnectionUri $uri -Authentication Kerberos

PS > $identity = 'Mailbox Database 0311695863'
PS > $sb = {(Get-MailboxDatabase -Status –Identity $identity).DatabaseSize.ToBytes()}
PS > Invoke-Command -Session $session -ScriptBlock $sb
159449088

 

And it worked, we can invoke methods in the remote session without having to parse strings. The final step was to create a separate environment, for admins only, one that doesn’t change the original configuration made by the Exchange team. I reverted back the value in the web.config file and wrote the following script to automate the process. Log on to your Exchange server, open PowerShell (not EMS) and run it (comments inline):

# load the IIS module
Import-Module WebAdministration

# get the path to the exchange server installation directory 
# and create a new folder for the exadmin application
$path = ‘HKLM:\SOFTWARE\Microsoft\ExchangeServer\v14\Setup’ $exbin = Join-Path (Get-ItemProperty $path).MsiInstallPath ClientAccess $folder = New-Item -Path $exbin\exadmin -ItemType Directory -Force # copy the web.config file to the new directory, load it (as xml) and
# change the language mode (from RestrictedLanguage) to FullLanguage Copy-Item $exbin\PowerShell\web.config $folder.FullName -Force [xml]$wconfig = Get-Content $exbin\exadmin\web.config $wconfig.configuration.appSettings.add.value = 'FullLanguage' $wconfig.Save("$exbin\exadmin\web.config") # Create a new IIS application pool, and start it $pool = New-WebAppPool -Name exadmin # Configure the exadmin app pool to run under the LocalSystem account (0) Set-ItemProperty IIS:\AppPools\exadmin -Name ProcessModel -Value @{identityType=0} # start app pool Start-WebAppPool -Name exadmin # Create a new IIS Web Application. $application = New-WebApplication -Name exadmin -Site 'Default Web Site' `
-PhysicalPath "$exbin\exadmin" -ApplicationPool $pool.name #Set the application SSL settings to accept client certificates (if they are provided) Set-WebConfigurationProperty -Filter //security/access –Name SslFlags `
-Value SslNegotiateCert -PSPath IIS:\ -Location 'Default Web Site/exadmin' # create new end point configuration and allow administrators to remotely run commands
# a dialog is shown with the local administrators group selected, and we can add
# users/groups we want to have access to the end point #Get-PSSessionConfiguration exadmin | Unregister-PSSessionConfiguration -Force Register-PSSessionConfiguration -Name exadmin -Force Set-PSSessionConfiguration -Name exadmin -ShowSecurityDescriptorUI -Force # testing the new environment, uncomment and change database identity # create a fan-in session (notice we are connecting to exadmin) and try to
# invoke the ToBytes method – it works
#$sb = { (Get-MailboxDatabase -Status -Identity 'Mailbox Database 0311695863').DatabaseSize.ToBytes() }
#$uri = ‘http://dc1.homelab.com/exadmin
#$session = New-PSSession -ConfigurationName Microsoft.Exchange –ConnectionUri $uri
#Invoke-Command $session –ScriptBlock $sb

Now you can connect from any computer that has PowerShell 2.0 installed to your Exchange server and gain full access. I hope this has been helpful, here’s some related resources you may find useful as well:

How objects are sent to and from remote sessions
Configuring PowerShell for Remoting – Part 1
Configuring PowerShell for Remoting – Part 2 (Fan-In)
Administrator's Guide to Windows PowerShell Remoting
Layman’s Guide to PowerShell 2.0 remoting
Deep Dive video: Constrained PowerShell Endpoints – Aleksandar Nikolic
Book: Microsoft Exchange 2010 PowerShell Cookbook - Mike Pfeiffer

Exchange - Removing Illegal Alias Characters using PowerShell

If you're in a mixed-mode environment with both Exchange 2003 and Exchange 2007/2010 you may have noticed this message when using the Get-* cmdlets in the Exchange Management Shell:

WARNING: The object domin.com/Users/UserName has been corrupted, and it's in an inconsistent state. The following validation errors happened:
WARNING: Property expression "xx xxx" isn't valid. Valid values are: Strings formed with characters from A to Z (uppercase or lowercase), digits from 0 to 9, !, #, $, %, &, ', *, +, -, /, =, ?, ^, _, `, {, |, } or ~. One or more periods may be embedded in an alias, but each period should be preceded and followed by at least one of the other characters. Unicode characters from U+00A1 to U+00FF are also valid in an alias, but they will be mapped to a best-fit US-ASCII string in the e-mail address, which is generated from such an alias.

Or one of the following:

WARNING: Object <distinguished name of the recipient> has been corrupted and it is in an inconsistent state. The following validation errors have been encountered:

WARNING: <alias of the recipient> is not valid for Alias.

 

These messages (there are others as well) appears when you try to manage a recipient with spaces (or any other invalid character) in its alias using the Exchange management tools. For example, in Exchange Server 2003, you could create recipients with spaces in aliases. Exchange Server 2007/2010 does not allow recipients to have spaces in their aliases. The biggest problem with invalid aliases - you will not be able to move a mailbox to an Exchange 2007/2010 server. To mitigate this I've written the following function.

Note: In Exchange 2010, the mailbox's alias is generated based on the Name property. Invalid characters in the name will be replaced with a question mark (?) when the alias is generated.

 

function Test-ExchangeAlias 
{
    param(
        [Parameter(
            Mandatory=$true,
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName=$true
        )]
        [ValidateLength(1,64)]
        [string]$Alias,
        
        [switch]$RemoveIllegalCharacters
    )
  
    begin
    {
        $IllegalCharacters = 0..34+40..41+44,47+58..60+62+64+91..93+127..160
    }
   
    process
    {        
        if($RemoveIllegalCharacters)
        {  
            foreach($c in $IllegalCharacters)
            {                
                $escaped = [regex]::Escape([char]$c)
                
                if($Alias -match $escaped)
                {
                    Write-Verbose "illegal character code detected: '$c'" 
                    $Alias = $Alias -replace $escaped
                }
            }
        
            $Alias
        }        
        else
        {            
            for($c=0; $c -lt $Alias.Length; $c++)
            {
                $code = [int][char]$Alias[$c]
                Write-Verbose "Testing current Alias character code: $code" 
                
                if($IllegalCharacters -contains $code)
                {
                    Write-Verbose "Character code: $code is an invalid alias character."
                    $false
                    return
                }
            }    
            
            $true
        }              
    }
}

The function supports two parameters, Alias and RemoveIllegalCharacters. In the Begin block we assign a series of numbers to a variable, $IllegalCharacters, using the range operator along with the plus operator (+) to combine a range with a list of elements in an array. These numbers represents the character codes an alias cannot contain.

In the Process block we check if the RemoveIllegalCharacters parameter has been specified. If it was specified, all invalid characters are removed and a fixed alias is returned. Otherwise the function just tests if the alias is valid and returns $true/$false respectively. Invalid characters are removed using the Replace operator. Since we don't know if each invalid character is a regular expression meta character we use the Escape method to convert it so that the regular expression engine will interpret any metacharacters that it may contain as character literals.

 

With the following command you can fix all invalid aliases on all mailbox objects:

Get-Mailbox –ResultSize Unlimited | Where-Object {-not (Test-ExchangeAlias -Alias $_.Alias)} | Foreach-Object {
     $NewAlias = Test-ExchangeAlias -Alias $_.Alias -RemoveIllegalCharacters
     $_ | Set-Mailbox –Alias $NewAlias
}

 

When running the above you’ll get the ‘inconsistent state’ error for each invalid alias mailbox object but if you issue the command again you’ll see that the error has gone and the Aliases have been fixed.

PowerSE - Free Professional Script Editor

imageA few days ago, Devfarm Software the makers of PowerWF, has released their commercial PowerShell editor, PowerSE v2.5, as a free community script editor.

PowerSE is an advanced script editor and an interactive console packed with multiple features to help you develop and debug your PowerShell scripts.  Now you can download a fully functional FREE version HERE (requires registration).

 

PowerSE features:

  • Complete IntelliSense coverage of PowerShell, DotNet and WMI.
  • Real time Syntax Checking instantly lets you see errors in your code and quickly jump to error lines to fix the problem.
  • It has an XML editor.
  • The ability to do a quick command.  Example.  Get-process.  Then using the grid, you can select columns, rearrange the rows, and sort.  Then generate the PowerShell, and insert it into your script.  Much faster than typing all those commands.
  • Integrated Help.
  • Tabbed interface to edit multiple scripts.
  • Integrated Console.  If you hit F11, it will zoom into full-screen mode (F11 to zoom back).  F12 will zoom the highlighted window to full-screen, and vice-versa.   F1 full-screen help.
  • Command History (combined with the console). So, you can do an interactive console session, to figure out what you need.  Then using the Command History, insert those command and create a script.  Sort of record/playback.
  • Call Stack history, plus complete debugger.
  • Search scripts in script repositories like: PoshCode and TechNet Script Center Repository.

 

Check out this video for a quick overview.

 

So, give it a spin to see how you like it. Thumbs up for making it free but there's one drawback, the product will expire in 60 days and to continue using it you will have to re-download it!

PowerShell MVP for 2011

July 1st is very special day for me. It is the day when I first got the MVP award.
Today I got it again, I'm a PowerShell MVP for the fourth year!

PowerShell At The Israeli SBS Users Group (Hebrew)

image

מה זה בכלל PowerShell? למה אני צריך את זה? בנות אוהבות את זה?

מה אם אף פעם לא כתבתי אפילו שורת פקודה אחת? אני בכלל לא מפתח – זה נוגע אלי?

המון שאלות אה?

על כל זאת ועוד נדבר במפגש הבא של קבוצת הדיון שייערך ב- 25/05/2011 בשעה 15:45 במשרדי מיקרוסופט, רעננה.

את יתר הפרטים תוכלו למצוא בהזמנה כאן: http://sbu.co.il/forum_posts.asp?TID=420&PID=1905

 

אין צורך בידע מוקדם, הביאו רק את עצמכם, ראש פתוח ומצב רוח טוב, השאר עלינו.

נתראה במפגש!

Learn Windows PowerShell in a Month of Lunches

imageLearn Windows PowerShell in a Month of Lunches is a newly designed tutorial for system administrators. Just set aside one hour a day -- lunchtime would be perfect -- for a month, and you'll be automating administrative tasks in a hurry. Author Don Jones combines his in-the-trenches experience with a unique teaching style to help you master the effective parts of PowerShell quickly and painlessly.

Who Should Read It

The book is written for administrators, not developers.

 

What's Inside

  • Learn PowerShell 2 from the beginning-no experience required!
  • Written especially for administrators, not developers
  • Practical examples and reusable techniques in every concise 1-hour lesson

 

About the Author

Don Jones has more than 15 years of IT experience, is the author of more than 35 books, and is a speaker at technology conferences such as Microsoft TechEd and Windows Connections. He's a multiple-year recipient of Microsoft's MVP award and is a technical guide for PowerShell for WindowsITPro.

Only for the next 24 hours you can use the lunchtoday promode and get a 50% discount!

Converting date strings in PowerShell

The Get-Date cmdlet lets us create, convert, and format date strings to DateTime .NET objects. However, there’s one thing it cannot do, convert a date string which is not a format it expects (defines by your system locale). For example, if your current culture is en-US you can pass a date string in the format of MM/dd/yyyy to the –Date parameter and Get-date will convert it to a DateTime object:

PS > Get-Date -Date 4/13/2011

Wednesday, April 13, 2011 12:00:00 AM

 

On the other hand, if we pass a string in the format of dd/MM/yyyy it fails:

PS > Get-Date -Date 13/4/2011

Get-Date : Cannot bind parameter 'Date'. Cannot convert value "13/4/2011" to type "System.DateTime". Error: "String was not recognized as a valid DateTime."

As you can see from the above error, Get-Date complains that "13/4/2011" was not in the correct format. A common case to this kind of date strings is when you have a third party application that writes date strings, not in the format of your locale, to log files. The only way to convert those strings to a valid DateTime object is to use the ParseExact static method of the DateTime .NET class. The ParseExact method is an overloaded member (we can invoke it in three ways, each with its own set of arguments). Instead of using the method directly I wrapped the first overload in an Advanced Function, ConvertFrom-DateString.

 

function ConvertFrom-DateString
{
    [OutputType(
'System.DateTime')]
    [CmdletBinding(DefaultParameterSetName
='Culture')]

  
param(
        [Parameter(
            Mandatory
=$true,
            Position
=0,
            ValueFromPipeline
=$true,
            HelpMessage
='A string containing a date and time to convert.'
        )]
        [
System.String]$Value,

        [Parameter(
            Mandatory
=$true,
            Position
=1,
            HelpMessage
='The required format of the date string value'
        )]
        [Alias(
'format')]
        [
System.String]$FormatString,
   
        [Parameter(ParameterSetName
='Culture')]
        [
System.Globalization.CultureInfo]$Culture=$null,

        [Parameter(Mandatory
=$true,ParameterSetName='InvariantCulture')]
        [
switch]$InvariantCulture
    )

  
process
    {
      
if($PSCmdlet.ParameterSetName -eq 'InvariantCulture')
        {
          
$Culture = [System.Globalization.CultureInfo]::InvariantCulture
        }

      
Try
        {           
                    [
System.DateTime]::ParseExact($Value,$FormatString,$Culture)
        }
      
Catch [System.FormatException]
        {
          
Write-Error "'$Value' is not in the correct format."
        }
      
Catch
        {
          
Write-Error $_       
        }
    }

  
<#
    .SYNOPSIS
        Converts a string representation of a date.

    .DESCRIPTION
        Converts the specified string representation of a date and time to its
        DateTime equivalent using the specified format and culture-specific format
        information. The format of the string representation must match the specified
        format exactly.

    .PARAMETER Value
        A string containing a date and time to convert.

    .PARAMETER FormatString
        The required format of the date string value. If FormatString defines a
        date with no time element, the resulting DateTime value has a time of
        midnight (00:00:00).
        If FormatString defines a time with no date element, the resulting DateTime
        value has a date of DateTime.Now.Date.

        If FormatString is a custom format pattern that does not include date or
        time separators    (such as "yyyyMMdd HHmm"), use the invariant culture
        (e.g [System.Globalization.CultureInfo]::InvariantCulture), for the provider
        parameter and the widest form of each custom format specifier.
        For example, if you want to specify hours in the format pattern, specify
        the wider form, "HH", instead of the narrower form, "H".

        The format parameter is a string that contains either a single standard
        format specifier, or one or more custom format specifiers that define the
        required format of StringFormats. For details about valid formatting codes,
        see 'Standard Date and Time Format Strings' (http://msdn.microsoft.com/en-us/library/az4se3k1.aspx)
        or 'Custom Date and Time Format Strings' (http://msdn.microsoft.com/en-us/library/8kb3ddd4.aspx).

    .PARAMETER Culture
         An object that supplies culture-specific formatting information about the
        date string value. The default value is null. A value of null corresponds
        to the current culture.

    .PARAMETER InvariantCulture           
        Gets the CultureInfo that is culture-independent (invariant). The invariant
        culture is culture-insensitive. It is associated with the English language
        but not with any country/region.            

    .EXAMPLE
        ConvertFrom-DateString -Value 'Sun 15 Jun 2008 8:30 AM -06:00' -FormatString 'ddd dd MMM yyyy h:mm tt zzz' -InvariantCulture
       
        Sunday, June 15, 2008 5:30:00 PM
       
        This example converts the date string, 'Sun 15 Jun 2008 8:30 AM -06:00',
        according to the specifier that defines the required format.
        The InvariantCulture switch parameter formats the date string in a
        culture-independent manner.
   
    .EXAMPLE
        'jeudi 10 avril 2008 06:30' | ConvertFrom-DateString -FormatString 'dddd dd MMMM yyyy HH:mm' -Culture fr-FR
       
        Thursday, April 10, 2008 6:30:00 AM
       
        In this example a date string, in French format (culture). The date string
        is piped to ConvertFrom-DateString. The input value is bound to the Value
        parameter. The FormatString value defines the required format of the date
        string value. The result is a DateTime object that is equivalent to the date
        and time contained in the Value parameter, as specified by FormatString and
        Culture parameters.

    .EXAMPLE   
        ConvertFrom-DateString -Value 'Sun 15 Jun 2008 8:30 AM -06:00' -FormatString 'ddd dd MMM yyyy h:mm tt zzz'

        Sunday, June 15, 2008 5:30:00 PM
       
        Converts the date string specified in the Value parameter with the
        custom specifier specified in the FormatString parameter. The result
        DateTime object format corresponds to the current culture.


    .INPUTS
        System.String
        You can pipe a string that contains a date and time to convert.

    .OUTPUTS
        System.DateTime

    .NOTES
        Author: Shay Levy
        Blog   : http://PowerShay.com

    .LINK
        http://msdn.microsoft.com/en-us/library/w2sa9yss.aspx
  
#>

}

ConvertFrom-DateString is decorated with Comment Based Help so you can use the Get-Help cmdlet to get help for its parameters as well as code examples. Let’s see how we can use the function to convert a date string to a DateTime object.


PS> 'Tue Mar 29 14:49:04 2011' | ConvertFrom-DateString -FormatString 'ddd MMM dd HH:mm:ss yyyy'

Tuesday, March 29, 2011 2:49:04 PM

 

The Value parameter accept pipeline input so we can pipe the string to the function. We also specify the format of the string, specifying each element position in the Format-String parameter. We didn’t specify the Culture parameter so the result is a DateTime object in the current culture of the local system. To get more help on .NET format specifiers, see "DateTimeFormatInfo Class" in the MSDN (Microsoft Developer Network) library at http://go.microsoft.com/fwlink/?LinkId=143638

 

Here’s another example with a French date string. This time we specify the string in the Value parameter and we also use the Culture parameter to tell the function that the string is in the fr-FR culture:

PS > ConvertFrom-DateString –Value 'jeudi 10 avril 2008 06:30' -FormatString 'dddd dd MMMM yyyy HH:mm' -Culture fr-FR
       
Thursday, April 10, 2008 6:30:00 AM
       

The function can also be downloaded from the TechNet Script Center Repository.

Enjoy!

Tied Variables in PowerShell

When PowerShell starts it creates a bunch of Automatic Variables. One of them is $PWD. $PWD contains a path object that represents the full path of the current directory (provider sensitive). Typically, when you assign a value to a variable, the value is evaluated once and from then on it's "static", each time you call the variable the returned value is always the same. The beauty of $PWD is that its value is calculated each time you call it.

PS> $PWD

Path
----
D:\scripts


PS > Set-Location HKLM:\SOFTWARE
PS > $PWD

Path
----
HKLM:\SOFTWARE

 

$PWD contains a rich .NET object (System.Management.Automation.PathInfo), not just a string path, so we can also interact directly with its members:

PS > $PWD.Provider.Name
Registry

 

I was trying to create a variable similar to $PWD ($Now) to get the current date and time, but no matter what I tried, the value of $Now always returned the same date and time. The reason behind creating $Now was this. Let's say you want to get the DayOfWeek value of a DateTime object, what we often do is:

## two lines of code
PS > $date  = Get-Date
PS > $date.DayOfWeek

Or

## using a .NET class
PS> [DateTime]::Now.DayOfWeek

Or

## enclosing in parenthesis
PS> (Get-Date).DayOfWeek

 

I wanted is to use the third example but avoid enclosing Get-Date it in parenthesis. One of the ways I was trying is with a function:

PS > function Now {Get-Date}

It works, I can now get a new fresh DateTime object each time I call the function, but I can't access the result object members without enclosing it in parenthesis:

PS> (Now).DayOfWeek

 

Ultimately, this is how I wanted it to be:

$Now.DayOfWeek

Simple to use and very short to type. Another thought was to create a new Alias but the result was the same as using a function, parenthesis were required to access object members. So I posted a question to the PowerShell MVP private list and soon enough Lee Holmes, pointed me to this blog post. Here's the code I used to create $Now:

Add-Type -TypeDefinition @"
using System;
using System.Management.Automation;
public class NowVariable : PSVariable
{
public NowVariable ()
  : base("Now", 0, ScopedItemOptions.ReadOnly | ScopedItemOptions.AllScope)
  {}
       public override object Value
        {
            get
            {
               return DateTime.Now;
            }
        }
}
"@

$ExecutionContext.SessionState.PSVariable.Set((New-Object -TypeName NowVariable))

 

Paste this code into your console and there you have it! A variable that evaluates its value each time you call it.

PS>$Now
Tuesday, April 12, 2011 10:48:41 AM

PS>$Now
Tuesday, April 12, 2011 10:48:43 AM

PS>$Now
Tuesday, April 12, 2011 10:48:45 AM

PS> $Now.DayOfWeek
Tuesday

 

Now we can access any member of the result DateTime object without parenthesis. Thanks Lee! The next step is to ask the PowerShell team to include $Now in the next version of PowerShell and the way to do that is to file a suggestion on the Microsoft Windows PowerShell Customer Connection website. The PowerShell team review the items suggested by the community and if it has enough votes it will find its (hopefully) way to the next version of PowerShell.

Do you want to have $Now as a new automatic variable in PowerShell 3.0? Vote it up HERE.

 

UPDATE: Check out this awesome post, by Robert Robelo, where he shows a how to get the same functionality in pure script and it also works in PowerShell v1!

 

The PowerShell Community Toolbar is Chrome supported!

I’m excited to announce that the PowerShell Community Toolbar is now supported on Google Chrome browsers. The new Chrome version is still in beta but is fully available for users who access any custom install page from Chrome (e.g. http://powershell.ourtoolbar.com/). It includes shiny new menus, support for toolbar gadgets, links, apps and much more.

 

 

The new version includes enhancements for look and feel for the RSS reader, Menu Buttons and Chevron. Currently, the toolbar does not support the Radio Player (podcasts) and the Weather components.

The PowerShell Community Toolbar has a Facebook group so come join us (if you haven’t done so yet) and get notifications when new stuff is added/removed, send feedback which you may have, technical issues, features you are missing, bugs, questions and any comment at all.

To download, on Google Chrome, go to: http://powershell.ourtoolbar.com/

Enjoy!

2011 Scripting Games

imageThe 2011 Scripting Games begin on April 4, 2011 and run through April 15, 2011. What is the Scripting Games, you may ask? Well simply put, the Scripting Games are the premier learning event of the year for IT Pro’s and others who wish to master Windows PowerShell. Comprising 10 events, a registered contestant has seven days to create a solution to a scenario driven problem and post their code to a MVP maintained script repository for evaluation by a panel of internationally recognized judges. Daily leaderboards and prize drawings help to maintain the suspense throughout the two-week international event.

During the 2011 Scripting Games hundreds of contestants will submit thousands of scripts that will be reviewed by dozens of judges. Hundreds of thousands of spectators from all around the world will view the games themselves. Last year, participants from more than 100 countries participated in the Scripting Games. With an emphasis on real world scripting scenarios and problems, the scripts will be of immediate value to both the participants and to the spectators.

Preparation for the 2011 Scripting Games is already underway, with a learning guide, step-by-step tutorials, videos and other resources being generated on a daily basis. The 2011 Scripting Games all in one page is the portal for the games themselves. The 2010 Scripting Games all in one page is still available, as are the events from the 2009 Scripting Games.

Grab the 2011 Scripting Games badge and display it on your blog to show your support for the games.

More Posts « Previous page - Next page »