April 2010 - Posts
You didn’t register for the games yet? Point your browser to http://2010sg.poshcode.org/ , create yourself a profile and submit your scripts.
Event 1, Updating and Creating Registry Keys, has released. Check THIS page regularly during the games, it has all the links you need on one page and it will be updated as new events release. Maybe you’ll be one of two lucky guys to attend TechEd 2010 North America for free ($2,195 value) or have a 15-minute phone conversation with Distinguished Engineer Jeffrey Snover :)
Looking for support and information, check the new 2010 Scripting Games Forum.
Good Luck!
Windows Server 2008 R2 includes a PowerShell module, ServerManager, for managing server roles, role services, and features via PowerShell cmdlets. In Windows 7, there is no such module and we need to use the GUI (OptionalFeatures.exe) or the ‘Deployment Image Servicing and Management’ tool (DISM, see list of resources below).
The problem with DISM, from a PowerShell perspective (objects, objects…), is that DISM is a legacy application that emits text and is not written with automation in mind .
PSClientManager is a PowerShell module that takes advantage of DISM and automates the task of adding and removing optional OS features by using four Advanced Functions. Each function runs DISM, parse its output and converts the result to custom objects.
- Add-ClientFeature
- Get-ClientFeature
- Get-ClientFeatureInfo
- Remove-ClientFeature
To get a quick look at all the the available features on your system, run the Get-ClientFeature without any parameters. One of the first features a system administrator would want to install is Telnet. Lets see how we can find and install it. We will run the Get-ClientFeature command and use a wildcard pattern for the feature name parameter.
PS > Get-ClientFeature –Name *telnet* | Format-Table -AutoSize
Name State
---- ------
TelnetServer Disabled
TelnetClient Disabled
The result shows that there are two Telnet features, Client and Server, and both are disabled. Lets get some more information about the client feature:
PS > Get-ClientFeatureInfo –Name TelnetClient
Name : TelnetClient
DisplayName : Telnet Client
RestartRequired : Possible
Properties :
Description : Connect to remote computers by using the Telnet protocol
State : Disabled
Now let’s enable it. Adding or removing features changes the system so the command asks for confirmation. To suppress confirmations use the –Force parameter or ‘-Confirm:$false’:
PS > Add-ClientFeature –Name TelnetClient
Confirm
Are you sure you want to perform this action?
Performing operation "Enable Feature 'TelnetClient'" on Target "PC1".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): y
Deployment Image Servicing and Management tool
Version: 6.1.7600.16385
Image Version: 6.1.7600.16385
Enabling feature(s)
[==========================100.0%==========================]
The operation completed successfully.
We can verify that the Telnet has been enabled by running the Get-ClientFeatureInfo or Get-ClientFeature.
PS > Get-ClientFeatureInfo –Name TelnetClient
Name : TelnetClient
DisplayName : Telnet Client
RestartRequired : Possible
Properties :
Description : Connect to remote computers by using the Telnet protocol
State : Enabled
PS > Get-ClientFeature Telnet* | Format-Table -AutoSize
Name State
---- ------
TelnetServer Disabled
TelnetClient Enabled
The functions can also pipe feature object(s) from one command to another. For example, the following command enables the Telnet client and server features on the current system (check help for a complete list of command parameters and code examples):
PS > Get-ClientFeature tel* | Add-ClientFeature
Gotcha: Feature names are case sensitive! Make sure you write them with the proper case.
The PSClientManager module is available for download at CodePlex in two forms, a zip file containing the source files or as an MSI package.
DISM Resources
Here’s a quick way to find out. Pipe the file to the New-TimeSpan cmdlet.
PS > Get-ChildItem foo.txt | New-TimeSpan
Days : 319
Hours : 7
Minutes : 8
Seconds : 48
Milliseconds : 409
Ticks : 275873284097833
TotalDays : 319.29778252064
TotalHours : 7663.14678049536
TotalMinutes : 459788.806829722
TotalSeconds : 27587328.4097833
TotalMilliseconds : 27587328409.7833
While playing around formatting dates I found that I can get a LONG list of DateTime patterns that I can use to format DateTime objects. The DateTimeFormatInfo.GetAllDateTimePatterns method returns all the standard patterns in which DateTime values can be formatted. DateTimeFormatInfo can be accesses via the DateTimeFormat member of the Get-Culture cmdlet (en-US):
PS > (Get-Culture).DateTimeFormat.GetAllDateTimePatterns()
M/d/yyyy
M/d/yy
MM/dd/yy
MM/dd/yyyy
yy/MM/dd
…
To view all patterns for different cultures (Hebrew) we need to create a new CultureInfo object:
PS > ([System.Globalization.CultureInfo]’he-IL’).DateTimeFormat.GetAllDateTimePatterns()
dd/MM/yyyy
dd/MM/yy
dd/MMMM/yyyy
dd-MM-yy
dd-MM-yyyy
…
To get a list of all CultureInfo objects that are installed in the Windows operating system:
PS > $InstalledWin32Cultures = [System.Globalization.CultureTypes]::InstalledWin32Cultures
PS > [System.Globalization.CultureInfo]::GetCultures($InstalledWin32Cultures)
LCID Name DisplayName
---- ---- -----------
127 Invariant Language (Invariant Country)
1025 ar-SA Arabic (Saudi Arabia)
1026 bg-BG Bulgarian (Bulgaria)
1027 ca-ES Catalan (Catalan)
1028 zh-TW Chinese (Taiwan)
1029 cs-CZ Czech (Czech Republic)
...
The following function can be used to display formatted dates for all patterns for a given culture. For each pattern we get, we use the DateTime.Parse Method to convert and format a date object to its DateTime equivalent using the specified CultureInfo object.
function Get-AllDateTimePatterns([string]$Culture=(Get-Culture).Name)
{
[Threading.Thread]::CurrentThread.CurrentCulture = $Culture
([System.Globalization.CultureInfo]$Culture).DateTimeFormat.GetAllDateTimePatterns() | Select-Object @{n='Pattern';e={$_}},@{n='Date';e={ ([DateTime]::Parse([DateTime]::Now.ToString(),$CultureInfo)).ToString($_)}}
}
Lets run the function for the Czech Republic culture:
PS > Get-AllDateTimePatterns –Culture cs-CZ
Pattern Date
------- ----
d.M.yyyy 17.4.2010
d-M-yy 17-4-10
yyyy-MM-dd 2010-04-17
yyyy-M-d 2010-4-17
yy-M-d 10-4-17
d. MMMM yyyy 17. dubna 2010
d. MMMM yyyy H:mm 17. dubna 2010 0:03
d. MMMM yyyy HH:mm 17. dubna 2010 00:03
d. MMMM yyyy h.mm tt 17. dubna 2010 12.03 dop.
d. MMMM yyyy H.mm 17. dubna 2010 0.03
d. MMMM yyyy H:mm:ss 17. dubna 2010 0:03:24
d. MMMM yyyy HH:mm:ss 17. dubna 2010 00:03:24
d. MMMM yyyy h.mm.ss tt 17. dubna 2010 12.03.24 dop.
d. MMMM yyyy H.mm.ss 17. dubna 2010 0.03.24
d.M.yyyy H:mm 17.4.2010 0:03
d.M.yyyy HH:mm 17.4.2010 00:03
d.M.yyyy h.mm tt 17.4.2010 12.03 dop.
d.M.yyyy H.mm 17.4.2010 0.03
d-M-yy H:mm 17-4-10 0:03
d-M-yy HH:mm 17-4-10 00:03
d-M-yy h.mm tt 17-4-10 12.03 dop.
d-M-yy H.mm 17-4-10 0.03
yyyy-MM-dd H:mm 2010-04-17 0:03
yyyy-MM-dd HH:mm 2010-04-17 00:03
yyyy-MM-dd h.mm tt 2010-04-17 12.03 dop.
yyyy-MM-dd H.mm 2010-04-17 0.03
yyyy-M-d H:mm 2010-4-17 0:03
yyyy-M-d HH:mm 2010-4-17 00:03
yyyy-M-d h.mm tt 2010-4-17 12.03 dop.
yyyy-M-d H.mm 2010-4-17 0.03
yy-M-d H:mm 10-4-17 0:03
yy-M-d HH:mm 10-4-17 00:03
yy-M-d h.mm tt 10-4-17 12.03 dop.
yy-M-d H.mm 10-4-17 0.03
d.M.yyyy H:mm:ss 17.4.2010 0:03:25
d.M.yyyy HH:mm:ss 17.4.2010 00:03:25
d.M.yyyy h.mm.ss tt 17.4.2010 12.03.25 dop.
d.M.yyyy H.mm.ss 17.4.2010 0.03.25
d-M-yy H:mm:ss 17-4-10 0:03:25
d-M-yy HH:mm:ss 17-4-10 00:03:25
d-M-yy h.mm.ss tt 17-4-10 12.03.25 dop.
d-M-yy H.mm.ss 17-4-10 0.03.25
yyyy-MM-dd H:mm:ss 2010-04-17 0:03:25
yyyy-MM-dd HH:mm:ss 2010-04-17 00:03:25
yyyy-MM-dd h.mm.ss tt 2010-04-17 12.03.25 dop.
yyyy-MM-dd H.mm.ss 2010-04-17 0.03.25
yyyy-M-d H:mm:ss 2010-4-17 0:03:25
yyyy-M-d HH:mm:ss 2010-4-17 00:03:25
yyyy-M-d h.mm.ss tt 2010-4-17 12.03.25 dop.
yyyy-M-d H.mm.ss 2010-4-17 0.03.25
yy-M-d H:mm:ss 10-4-17 0:03:25
yy-M-d HH:mm:ss 10-4-17 00:03:25
yy-M-d h.mm.ss tt 10-4-17 12.03.25 dop.
yy-M-d H.mm.ss 10-4-17 0.03.25
dd MMMM 17 dubna
dd MMMM 17 dubna
yyyy'-'MM'-'dd'T'HH':'mm':'ss.fffffffK 2010-04-17T00:03:25.0000000
yyyy'-'MM'-'dd'T'HH':'mm':'ss.fffffffK 2010-04-17T00:03:25.0000000
ddd, dd MMM yyyy HH':'mm':'ss 'GMT' so, 17 IV 2010 00:03:25 GMT
ddd, dd MMM yyyy HH':'mm':'ss 'GMT' so, 17 IV 2010 00:03:25 GMT
yyyy'-'MM'-'dd'T'HH':'mm':'ss 2010-04-17T00:03:25
H:mm 0:03
HH:mm 00:03
h.mm tt 12.03 dop.
H.mm 0.03
H:mm:ss 0:03:25
HH:mm:ss 00:03:25
h.mm.ss tt 12.03.25 dop.
H.mm.ss 0.03.25
yyyy'-'MM'-'dd HH':'mm':'ss'Z' 2010-04-17 00:03:25Z
d. MMMM yyyy H:mm:ss 17. dubna 2010 0:03:25
d. MMMM yyyy HH:mm:ss 17. dubna 2010 00:03:25
d. MMMM yyyy h.mm.ss tt 17. dubna 2010 12.03.25 dop.
d. MMMM yyyy H.mm.ss 17. dubna 2010 0.03.25
MMMM yyyy duben 2010
MMMM yyyy duben 2010
Finally, the GetAllDateTimePatterns method has another useful overload we can use to get all the standard patterns using a specified format character. For example, we can get all patterns associated with ‘d’:
PS > (Get-Culture).DateTimeFormat.GetAllDateTimePatterns('d')
M/d/yyyy
M/d/yy
MM/dd/yy
MM/dd/yyyy
yy/MM/dd
yyyy-MM-dd
dd-MMM-yy
Do you happen to know or have a rough guess when exactly your mailbox was created? From a client perspective (Outlook), you can get the date quite easily. One thing you do need to know in advance is the property tag for the PR_CREATION_TIME property name. We can get that with MFCMapi.
Download MFCMapi HERE and launch it. From the menu, click ‘Session’ and choose the first menu item: ‘Logon And Display Store Table’
Choose the Outlook profile you want to load and press OK.
Double click your mailbox store…
A new dialog pops up, click ‘Root – Mailbox’ on the left hand side pane, look for the PR_CREATION_TIME property in the right pane and double click it. Copy the value of ‘DASL’.
You can now close MFCMapi. Here’s the PowerShell code to get the creation time of the mailbox. I should add that I tested it with Outlook 2007, earlier versions of Outlook has different object model and the code may not work.
PS > $PR_CREATION_TIME = "http://schemas.microsoft.com/mapi/proptag/0x30070040"
PS > $outlook = New-Object -ComObject Outlook.Application
PS > $DefaultStore = $outlook.Session.DefaultStore.GetRootFolder()
PS > $DefaultStore.PropertyAccessor.GetProperty($PR_CREATION_TIME)
Monday, December 28, 2009 1:49:01 PM
Which you can also write as a one-liner :)
(New-Object -ComObject Outlook.Application).Session.DefaultStore.GetRootFolder().PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x30070040")