DCSIMG
April 2011 - Posts - Shay Levy

Shay Levy

If you repeat it, PowerShell it!

April 2011 - Posts

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!