Yesterday I saw a tweet that caught my eye:

Sounds familiar? What do you usually do to reconnect to your server once it is back online? How do you monitor it’s availability? In this post, Justin shares a great function (115 lines) that restarts a server, waits for it to come back online and then starts a remote desktop connection to it.
Now, what if I told you that in PowerShell 3.0 you can replace that function with only two lines of code?
In PowerShell 3.0, the Restart-Computer cmdlet got improved (mainly to support Workflow scenarios) and it now supports a few more parameters, notably the –Wait and –For parameters. When –Wait is specified, the command waits for all of the following service types to be available (can take a lot of time) before you can proceed to the next line of code. The following command lists the service types:
PS> [Enum]::GetNames(‘Microsoft.PowerShell.Commands.WaitForServiceTypes’)
Wmi
WinRM
PowerShell
Actually, these types are the possible values of the –For parameter. In the previous CTP version, there used to be a ‘Network’ type too, but looks like it was removed. We can specify one of above types, Restart-Computer waits for that component only to be available and then the rest of our code is executed.
In our case, we need to wait for the Remote Desktop Services service to start, but there’s no related service type we can use for that. We can wait for the ‘Wmi’ service. That’s because the WMI and the RDS services are dependent on the Remote Procedure Call (RPC) service, so if the WMI service is started we can assume that the RDS service is up as well.
Restart-Computer –ComputerName Server1 -Wait -For Wmi –Force
mstsc –v Server1 /admin
That’s all it takes to connect to Server1 once it’s back online. Notice that the Restart-Computer command may fail if there are users logged on to the remote computer or if there are opened applications, so make sure you include the –Force switch. One “caveat” though, the command waits until the computer has finished restarting and doesn’t give back your prompt, you’re stuck waiting for it to finish. To continue working you can spin a new background job:
Start-Job -ScriptBlock{
Restart-Computer –ComputerName $args[0] -Wait -For Wmi–Force
mstsc -v $args[0] /admin
} -ArgumentList Server1

One of the new improvements in the .NET Framework version 4 is the Microsoft.Win32.RegistryView enumeration.
On the 64-bit version of Windows, portions of the registry are stored separately for 32-bit and 64-bit applications. There is a 32-bit view for 32-bit applications and a 64-bit view for 64-bit applications. Many of the 32-bit keys have the same names as their 64-bit counterparts, and vice versa. In the 64-bit version of Registry Editor, 32-bit keys are displayed under the following registry key: HKEY_LOCAL_MACHINE\Software\WOW6432Node.
I’m pleased to announce that the PSRemoteRegistry module has a new version specifically for PowerShell v3 that implements the new feature mentioned above. The new module, now called PSRR (to avoid name collisions with the previous module and to allow you to type less when you load it), was rewritten and is using the new language features introduced in PowerShell v3. To improve the readability of the functions, all functions' help are now stored in MAML files (instead of comment-based help).
The major addition to the PSRR module is the ability to manage both 64-bit and 32-bit registry keys and values by using the new View parameter (available on all module functions) from PowerShell x86 or x64 instances. See the help for any function on how to use theView Parameter.
You can download it HERE.
PowerShell Magazine has started the PowerShell Experts Video Series, a series of short video interviews conducted at the PowerShell Deep Dive conference in Frankfurt, Germany.
Starting today, we will post one video interview per day. The first one is with MVP Dmitry Sotnikov.
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 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.
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.
I’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 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:

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
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.
A 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!
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? למה אני צריך את זה? בנות אוהבות את זה?
מה אם אף פעם לא כתבתי אפילו שורת פקודה אחת? אני בכלל לא מפתח – זה נוגע אלי?
המון שאלות אה?
על כל זאת ועוד נדבר במפגש הבא של קבוצת הדיון שייערך ב- 25/05/2011 בשעה 15:45 במשרדי מיקרוסופט, רעננה.
את יתר הפרטים תוכלו למצוא בהזמנה כאן: http://sbu.co.il/forum_posts.asp?TID=420&PID=1905
אין צורך בידע מוקדם, הביאו רק את עצמכם, ראש פתוח ומצב רוח טוב, השאר עלינו.
נתראה במפגש!
Learn 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!
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!
More Posts
Next page »