Showing posts with label powershell. Show all posts
Showing posts with label powershell. Show all posts

Tuesday, November 10, 2009

Create an XML Schema Enumeration of Supported .NET CultureInfo with Powershell

Here’s a Powershell script to generate the enumeration elements of an XML Schema simpleType restriction.  The first command loads the .NET Assembly you’ll need, sysglobl.dll.

PS> [System.Reflection.Assembly]::Load("sysglobl, Version=2.0.0.0, Culture=neutral, PublicKeyToken= b03f5f7f11d50a3a, processorArchitecture=MSIL")
PS> [System.Globalization.CultureInfo]::GetCultures([System.Globalization.CultureTypes]::FrameworkCultures)
| ? {$_.Name.Trim().Length -eq 5} | % { "<xs:enumeration value=`"$_`"/>"} | Out-File cultures.txt

See my earlier post on locale identifiers for more background.

Sunday, August 2, 2009

Powershell: Get Size of Child Directories

gci -recurse -force |
? { $_.GetType() -like 'System.IO.DirectoryInfo'} |
     select-object Name,@{Name="size"; Expression = {
    ($_.GetFiles()  |
    Measure-Object -Property Length -Sum |
     Measure-Object -Property Sum -Sum).Sum}} | sort-object -Property size

Tuesday, June 16, 2009

Value Objects and Value Domains

I’ve written relatively extensively on the topic of replacing enum constructs with classes, so I won’t rehash the topic. Instead, I’d like to introduce you to some code I’ve written that enables you to create finite domains of Value Objects in C#.  Please see my two previous posts on the subject to learn more about the benefits of this approach.  To see how the Value Object semantics and making a finite domain a first class concept in the pattern improves the approach, read on.

First, we need some definitions.  We are taking the concept of a Value Object from Eric Evans’ book “Domain Driven Design” p.99:

When you care only about the attributes of an element of the model, classify it as a Value Object. Make it express the meaning of the attributes it conveys and give it related functionality. Treat the Value Object as immutable.  Don’t give it any identity […] The attributes that make up a Value Object should form a conceptual whole.

An example here is useful.  Consider modeling the domain of a book publisher.  At some point you need to capture all the different formats of books: A4, B, Pinched Crown, etc.  The attributes of width, height, unit of measure, and name would go into your model.  But, any instance of your A4 Value Object should be completely interchangeable from any other A4.  And, it goes without saying that you can’t change the width or height or any other attribute of A4.

All of the different formats of books belong to a Value Domain. According to WordNet, a domain (we are using the mathematical notion) is:

the set of values of the independent variable for which a function is defined

The functional complement of a domain is the range of the function; i.e. domain is what you can put in, the range is what you can expect to get out.  I like calling this concept in my approach a domain instead of a set, because it neatly captures a key benefit.  When we are writing code.  We want to declare our parameters as being a proper member of domain of values, instead of just primitive types or strings.

Now we’re ready to dive into the implementation.  Let’s begin with the end in mind.  I want to write a function, say, that let’s me search for a document with a particular format about an arbitrary topic.

void SearchDocs(DocFormat docFormat, string topic)


Ok, so we could create a base class or an interface called DocFormat and create Word doc, PDF, etc. that inherit from or implement DocFormat.  Easy.  But, SearchDocs has to be able to handle all current and future implementations of DocFormat; it must not violate the Liskov substitution principle. What if the repository or search algorithm depends on the what the doc format actually is?  Also, we’d have a subclass of DocFormat to write for every document type, and we’d have to do a lot of work to remove object identity, since your instance of PDF is not the same as my instance of PDF.  And, don’t forget to make the whole thing immutable. [Note: I know this is a contrived example with well-established OOP solutions that don’t require LSP violation.  Work with me here. :)]



Clearly we have a lot of work to do to make our Value Objects a reality.  It’s not impossible, though, and a quick Bing Google turns up a couple of investigations and approaches.  Jimmy Bogard’s approach gave me a clue that I needed to get it working.  What I wanted was a base type, ValueObject, that I could inherit from and get the Value Object semantics described in Evans.



Jimmy’s approach used a self-referencing open constructed type to allow the ValueObject base class to do all the work of providing Value Object semantics.  This base class uses dynamic reflection to determine what properties to use in the derived class to do equality comparisons (an approach nominally improved upon here). He saw his approach as having a single fundamental flaw; it only worked for the first level of inheritance, i.e. the first descendent from ValueObject.



For my purposes—creating a bounded, finite domain of Value Objects to replace enum-type classes--this is not a flaw.  Substantively, all that remains to do is introduce the concept of the the Value Domain into Jimmy’s approach and put the Value Objects in it.  Because I wanted to use these Value Domains throughout the enterprise, I baked WCF support into my approach.  Further, because the Value Domain is defined a priori, I didn’t have to play with object identity; I could simply look the value up in the domain.  (It took a little out-of-the-box thinking to get that to work transparently.)  Finally, I wanted it to be trivially easy to create these Value Domains, so I created a snippet for use in Visual Studio.



Here’s an example of Value Domain and Value Objects implementation:



[DataContract]
public sealed class DocFormats : ValueObject<DocFormats.DocFormat, string, DocFormats>.Values<DocFormats>
{
private DocFormats()
{
Word = Add("Word");
PDF = Add("PDF");
}

[DataMember]
public readonly BindingType Word, PDF;

[Serializable]
public sealed class DocFormat : ValueObject<DocFormat, string, DocFormats>
{
private DocFormat(string v) : base(v) { }
}
}



DocFormats is the Value Domain.  DocFormat is the type of the Value Object.  String is the underlying type of the values, but the pattern supports anything that implements IEquatable and IComparable.  Methods can accept DocFormats.DocFormat as a parameter and only Word and PDF will be valid.  Code can specify those values through a Singleton accessor: DocFormats.Instance.PDF.  You’ll notice that the only constructor is private; the Singleton implementation is in the base value domain base class (ValueObject<…>.Values<…>).



// our new method interface
void SearchDocs(DocFormats.DocFormat docFormat, string topic)
{
// referencing an individual value
if(DocFormats.Instance.Word == docFormat)
{
//...
}
}



Above you’ll note that the Value Object type definition (subclass of ValueObject<…>) is nested inside of the Value Domain.  Doing that groups the two together syntactically in a very natural way (FooTypes.FooType); the entire domain of values is contained in one place.  That locality makes the snippet to produce them cohesive too.  [Note: I’ve included the snippet XML at the end of this post.]



Interestingly, the underlying implementation necessarily inverts this nesting; the Value Domain base class is nested in the Value Object base class.  That allows the Value Domain Singleton to create instances of Value Objects.  I only had to resort to reflection in order to allow the Value Domain base class to provide the Singleton implementation.  Inversion of Control containers like Unity and Castle Windsor do this kind of reflection all the time, and it’s cheap since .NET 2.0. 



Without further ado, here’s the base classes implementation.



using System;
using System.Collections.Generic;
using System.Reflection;

[Serializable]
public abstract class ValueObject<T, TValue, TValues> : IEquatable<T>, IComparable, IComparable<T>
where T : ValueObject<T, TValue, TValues>
where TValue : IEquatable<TValue>, IComparable<TValue>
where TValues : ValueObject<T, TValue, TValues>.Values<TValues>
{
/// <summary>
///
This is the encapsulated value.
/// </summary>
public readonly TValue Value;
protected ValueObject(TValue value)
{
Value = value;
}

#region equality
public override bool Equals(object other)
{
return other != null && other is T && Equals(other as T);
}

public override int GetHashCode()
{
// TODO provide an efficient implementation
// http://www.dotnetjunkies.com/weblog/tim.weaver/archive/2005/04/04/62285.aspx
return Value.GetHashCode();
}

public bool Equals(T other)
{
return other != null && Value.Equals(other.Value);
}

public static bool operator ==(ValueObject<T, TValue, TValues> x, ValueObject<T, TValue, TValues> y)
{
// pointing to same heap location
if (ReferenceEquals(x, y)) return true;

// both references are null
if (null == (object)(x ?? y)) return true;

// auto-boxed LHS is not null
if ((object)x != null)
return x.Equals(y);

return false;
}

public static bool operator !=(ValueObject<T, TValue, TValues> x, ValueObject<T, TValue, TValues> y)
{
return !(x == y);
}
#endregion

public static implicit operator
TValue(ValueObject<T, TValue, TValues> obj)
{
return obj.Value;
}

public static implicit operator ValueObject<T, TValue, TValues>(TValue val)
{
T valueObject;
if (Values<TValues>.Instance.TryGetValue(val, out valueObject))
return valueObject;

throw new InvalidCastException(String.Format("{0} cannot be converted", val));
}

public override string ToString()
{
return Value.ToString();
}

#region comparison

public int CompareTo(T other)
{
return Value.CompareTo(other);
}

public int CompareTo(object obj)
{
if (null == obj)
throw new ArgumentNullException();

if (obj is T)
return Value.CompareTo((obj as T).Value);

throw new ArgumentException(String.Format("Must be of type {0}", typeof(T)));
}

#endregion

[Serializable]
public abstract class Values<TDomain> where TDomain : Values<TDomain>
{
[NonSerialized]
protected readonly Dictionary<TValue, T> _values = new Dictionary<TValue, T>();

private void Add(T valueObject)
{
_values.Add(valueObject.Value, valueObject);
}

protected T Add(TValue val)
{
var valueObject = typeof(T).InvokeMember(typeof(T).Name,
BindingFlags.CreateInstance | BindingFlags.Instance |
BindingFlags.NonPublic, null, null, new object[] { val }) as T;
Add(valueObject);
return valueObject;
}

public bool TryGetValue(TValue value, out T valueObject)
{
return _values.TryGetValue(value, out valueObject);
}

public bool Contains(T valueObject)
{
return _values.ContainsValue(valueObject);
}

static volatile TDomain _instance;
static readonly object Lock = new object();
public static TDomain Instance
{
get
{
if (_instance == null)
lock (Lock)
{
if (_instance == null)
_instance = typeof(TDomain)
.InvokeMember(typeof(TDomain).Name,
BindingFlags.CreateInstance |
BindingFlags.Instance |
BindingFlags.NonPublic, null, null, null) as TDomain;
}
return _instance;
}
}
}
}



I’d love to hear your feedback.  This is approach is not intended to support unbounded Value Domains, such as the canonical example of Address.  It is meant for the enums-as-classes problem, i.e. finite, bounded Value Domains.



ValueObject.snippet



<?xml version="1.0" encoding="utf-8" ?>
<
CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
<
CodeSnippet Format="1.0.0">
<
Header>
<
Title>ValueOjbect</Title>
<
Shortcut>vo</Shortcut>
<
Description>Code snippet for ValueObject and domain</Description>
<
Author>Christopher Atkins</Author>
<
SnippetTypes>
<
SnippetType>Expansion</SnippetType>
</
SnippetTypes>
</
Header>
<
Snippet>
<
Declarations>
<
Literal>
<
ID>domain</ID>
<
ToolTip>Value domain name</ToolTip>
<
Default>MyValues</Default>
</
Literal>
<
Literal>
<
ID>value</ID>
<
ToolTip>ValueObject Class name</ToolTip>
<
Default>MyValueObject</Default>
</
Literal>
<
Literal>
<
ID>type</ID>
<
ToolTip>Value Type</ToolTip>
<
Default>string</Default>
</
Literal>
</
Declarations>
<
Code Language="csharp">
<![CDATA[
[DataContract]
public sealed class $domain$ : ValueObject<$domain$.$value$, $type$, $domain$>.Values<$domain$>
{
private $domain$()
{
Value1 = Add(String.Empty);
}

[DataMember]
public readonly $value$ Value1;

[Serializable]
public sealed class $value$ : ValueObject<$value$, $type$, $domain$>
{
private $value$($type$ v) : base(v) { }
}
}
]]>
</
Code>
</
Snippet>
</
CodeSnippet>
</
CodeSnippets>

Tuesday, November 4, 2008

Dealing with Globalization Differences in Windows Versions

Recently I was charged with leading an effort to localize an ASP.NET application to a few different locales, including The Netherlands and India.  I was reminded again how difficult it is to get this right.  There are those who argue that using the same view across all the cultures supported in your application is a bad idea.  For example, an RTL culture, e.g. Hebrew, when done right, requires a mirroring of the entire view layout: not an easy thing to accomplish without changing the view.

Regardless, the .NET Framework and ASP.NET provide many facilities for localizing your application around a single view: App_LocalResources, App_GlobalResources, CultureInfo, etc.  ASP.NET has a particularly helpful feature; you can set the CultureInfo used by the application in the web.config using the globalization element.

There are lots of different ways of representing a culture in Windows: culture name, culture identifier, locale identifier (LCID), and others.  Generally, though, the culture name is used, e.g. en-US, en-GB, and es-MX for English (US), English (Great Britain), and Spanish (Mexico), respectively.  As the world's second most populous country with many ancient and highly varied cultures, India have no less than nine culture names defined in the .NET Framework.  This is, however, a narrow view of India's diversity with its 28 states, 7 union territories, and literally hundreds of spoken languages.  Obviously, there isn't 100% coverage of this diversity in the cultures supported in .NET.

One particularly useful culture name in use in Windows is en-IN.  In India, the de facto language of the law and by extension government and business is English, due to both the historical influence of British colonization and the need for a lingua franca in such an amazingly diverse country.  The en-IN culture code codifies this, making it possible for an application developer to effectively gloss over this diversity in the Indian market.  Unfortunately, en-IN is not available in the core .NET Framework release.  As you can see from this list, Windows Vista supports this culture, as does Windows 2008.

Obviously, this is problematic for developers doing development on Vista but deploying to Windows 2003 R2.  Fortunately, Microsoft developers faced with the incredible diversity of the world's cultures provided a way to customize the available cultures on any Windows installation: the CultureAndRegionInfoBuilder (CARIB) class.  There is a standard how-to create custom cultures with this class, but we will take a slightly different approach in this entry.  We will export the en-IN culture from our Windows Vista development machine, and import it on our Windows 2003 R2 server.

We'll use PowerShell here, but the examples should be clear enough that you can write your own console or Windows application to execute these steps.  Let's begin with exporting the en-IN culture.  The CARIB class is in sysglobl.dll, so we need a "reference" to that assembly. We can load the assembly from the GAC in PowerShell.  To do so we use its strong name, obtained by using "gacutil /l sysglobl" from a Visual Studio command prompt. In PowerShell on the Vista machine,

PS> [System.Reflection.Assembly]::Load("sysglobl, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL")

Now that we can reference the class, let's export the culture into an industry standard format called Locale Data Markup Language (LDML) version 1.1 using the Save method.  We can import this later with the CreateFromLdml method.

PS> $enIN = New-Object System.Globalization.CultureAndRegionInfoBuilder("en-IN", "Replacement")
PS> $enIN.LoadDataFromCultureInfo((New-Object System.Globalization.CultureInfo("en-IN")))
PS> $enIN.LoadDataFromRegionInfo((New-Object System.Globalization.RegionInfo("IN")))
PS> $enIN.Save("enIN.ldml")

Now we can copy enIN.ldml to our server and import it.  There are three very important modification we must make to enIN.ldml, however.  The en-IN culture is defined in terms of some other Windows locale information that won't be found on Windows 2003 R2, specifically "text info", "sort", and "fallback".  If you open enIN.ldml, you'll find the following three elements.

<msLocale:textInfoName type="en-IN" />
<msLocale:sortName type="en-IN" />
...
<msLocale:consoleFallbackName type="en-IN" />

If we try to load a CARIB from this file as-is, we'll receive the following error.  For more information, see the section "Exporting Operating System-Specific Cultures" in this CodeProject on-line book.

Culture name 'en-in' is not supported.

We've got to change these to a sensible alternative that is supported on Windows 2003 R2.  I chose "en-US", though "en-GB" would've also been appropriate.  For other cultures, this may prove more difficult.  My changed LDML file contains these lines.

<msLocale:textInfoName type="en-US" />
<msLocale:sortName type="en-US" />
...
<msLocale:consoleFallbackName type="en-US" />

With that done, we can load and register the culture on the Windows 2003 server.

PS> [System.Reflection.Assembly]::Load("sysglobl, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL")
PS> $enIN = [System.Globalization.CultureAndRegionInfoBuilder]::CreateFromLdml("enIN.ldml")
PS> $enIN.Register()

The culture en-IN is now available to all applications running on your server.  To see this in action, you could now augment the web.config of you web application with a globalization element:

...
<system.web>
  <globalization culture="en-IN" uiCulture="en-IN" />
...


Create a file called i18n.aspx and add the following code:

<%@ Page Language="C#"%>
<% = (10.5).ToString("c") %>

Navigate to i18n.aspx and you should see the following:

Rs. 10.50

I hope this helps!

Thursday, June 5, 2008

PowerShell: Convert Unix line-ending to Windows CrLf

function GetFiles
{
  foreach ($i in $input) {
   ? -inputObject $i -filterScript { $_.GetType().Name -eq "FileInfo" }
  }
}

function ConvertToCrLf
{
  param([string] $path)
  gci $path |
  GetFiles |
  % {
    $c = gc $_.FullName
    $c | % {
             if (([regex] "`r`n$").IsMatch($_) -eq $false) {
               $_ -replace "`n", "`r`n"
             } else {
               $_
             }
           } |
        set-content $path
  }
}

Monday, April 28, 2008

Take Ownership and Full Control in Vista

Sometimes you move a bunch of files from an old machine, in a different domain, and you want to modify those files in the new environment.  Generally, the process is to take ownership of the files, then grant yourself full control.  This can be a tedious process in Windows Vista, especially in light of LUA.  So, I present here some scripting you can use from PowerShell perform this burdensome task.

First, taking ownership is still best accomplished using the "takeown" command.  You can look the command syntax up, but if you wanted to take ownership of all the files in the current directory, you can do this from your PowerShell prompt:

gci | % { takeown /f $_}

Next, you want to grant yourself full control.  This is normally done with the cacls command, but in Windows Vista this has been deprecated and you should use the icacls command.  Here's how to grant yourself full control on all the files in the current directory, replacing your current permissions:

gci | % { icacls $_.FullName /grant:r your_domain\your_username:F }

Replace your_domain and your_username above with the information appropriate to your environment.

Monday, December 10, 2007

Convert SID to NTAccount with Powershell

Here's a quick script to convert a given SID (e.g. S-1-0-234...) to a NT Account (e.g. DOMAIN\user):

$sid = new-object System.Security.Principal.SecurityIdentifier "S-1-0-234..."

$ntacct = $sid.Translate([System.Security.Principal.NTAccount])

Wednesday, December 5, 2007

Powershell Script to Add an Event Log

When setting up logging for your ASP.NET application, you may want to write to a custom Event Log. If you do not install your web application, however, you may be dismayed that the service account for your web application does not have sufficient permissions to create an Event Log when you write to it.



Here is a PowerShell script to help you out:



$creationData = new-object System.Diagnostics.EventSourceCreationData "AppName", "LogName"
$creationData.MachineName = "TargetServerName"
[System.Diagnostics.EventLog]::CreateEventSource($creationData)

Wednesday, July 25, 2007

A PowerShell Script to Determine Directory Size

Here's a script I wrote to determine the size (in megabytes) of all the files in a directory and its subdirectories. This should be a bit more accurate, if less precise, than what you get in Windows Explorer.




function GetSize()
{
$size= gci -recurse -force |
? { $_.GetType() -like 'System.IO.DirectoryInfo'} |
% {$_.GetFiles() } |
Measure-Object -Property Length -Sum |
Measure-Object -Property Sum -Sum

$size2 = (Get-item .).GetFiles() |
Measure-Object -Property Length -Sum

[System.Math]::Round(($size.Sum + $size2.Sum) /
(1024 * 1024)).ToString() + "MB"
}