PowerShell Remoting Project Home

Friday, January 27, 2006

Dreaming of SU in MSH?

(Added on Mar 6th) There is a follow up post on this topic here.

Shame on myself! I should do more research before posting a blog entry. MoW already had a similar script a couple of months ago.

Want to run a MSH script as another windows user? You got it now! I am not talking about Runas.exe. It is a MSH script to start new msh.exe process with a differnt windows identity. Just like su.exe in Linux.

###########################################
# File Name: su.msh
# Launch a new msh.exe with someone else's identity
# from tony http://mshforfun.blogspot.com/
###########################################
$SuAccount = get-credential
$StartInfo = new-object System.Diagnostics.ProcessStartInfo
$StartInfo.FileName = "msh.exe"
$StartInfo.UserName = $SuAccount.UserName
$StartInfo.Password = $SuAccount.Password
$StartInfo.LoadUserProfile = $true
$StartInfo.UseShellExecute = $false
$StartInfo.WorkingDirectory = (get-location).Path
[System.Diagnostics.Process]::Start($StartInfo)

Added on 23rd Feb 2006, 08:40
Jeffrey Snover Suggested to add the following line:
$StartInfo.Arguments="-noexit -command `$Host.UI.RawUI.WindowTitle=\`"Microsoft Command Shell ($($SuAccount.UserName)) \`""
Added on 23rd Feb 2006, 08:40


Added on 27th Jan 2006, 15:46
In Monad beta3 version, the default behavior of get-credential was changed to "CredUI". "CredUI returns a username with "\" prepended. When passing that to the Process.Start method, it has intermittent difficulty dealing with that form of a username. " --Lee Holmes
To change it back to CLI, run following script:
new-property HKLM:\SOFTWARE\Microsoft\MSH\1\ShellIds `
-property ConsolePrompting -value "True" -force

See newsgroup thread here for details. Also checkout ::: MSH ::: Blog Entry for this issue.
/Added on 27th Jan 2006, 15:46

So if you were a non-privilege user "testac" , you run id.msh:
UserSID= S-1-5-21-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxx (Domain\testac)
AuthenticationType= NTLM
ImpersonationLevel= None
Token= xxxx
Groups=
GroupSID= S-1-5-21-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxx (Domain\None)
GroupSID= S-1-1-0 (Everyone)
GroupSID= S-1-5-32-545 (BUILTIN\Users)
GroupSID= S-1-5-4 (NT AUTHORITY\INTERACTIVE)
GroupSID= S-1-5-11 (NT AUTHORITY\Authenticated Users)
GroupSID= S-1-2-0 (LOCAL)


After su to an Administrator user "tony". Then you run id.msh again in new msh.exe window:
UserSID= S-1-5-21-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxx (Domain\tony)
AuthenticationType= MICROSOFT_AUTHENTICATION_PACKAGE_V1_0
ImpersonationLevel= None
Token= xxxx

Groups=

GroupSID= S-1-5-21-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxx (Domain\None)

GroupSID= S-1-1-0 (Everyone)

GroupSID= S-1-5-32-544 (BUILTIN\Administrators)
GroupSID= S-1-5-32-545 (BUILTIN\Users)
GroupSID= S-1-5-4 (NT AUTHORITY\INTERACTIVE)
GroupSID= S-1-5-11 (NT AUTHORITY\Authenticated Users)

GroupSID= S-1-2-0 (LOCAL)

Have Fun!

[Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.]

Tags:       



Tuesday, January 24, 2006

A Clone of id/whoami in MSH

I would like to have something like id/whoami in linux while working with MSH. So I wrote a simple script.
##############################################
# File Name: id.msh
# Return User and Group information of current logon user
# By Tony http://mshforfun.blogspot.com
##############################################
$me=[System.Security.Principal.WindowsIdentity]::GetCurrent()
"UserSID= " + $me.User + " (" + $me.Name + ")"
"AuthenticationType= " + $me.AuthenticationType
"ImpersonationLevel= " + $me.ImpersonationLevel
"Token= " + $me.Token
"Groups= "
foreach($Group in $me.Groups)
{
"`tGroupSID= " + $Group + " (" + $Group.Translate([System.Security.Principal.NTAccount]) + ")"
}
Output looks like:
UserSID= S-1-5-21-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxxx (Domain\me)
AuthenticationType= NTLM
ImpersonationLevel= None

Token= xxxx

Groups=
GroupSID= S-1-5-21-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx-xxx (Domain\None)
GroupSID= S-1-1-0 (Everyone)
GroupSID= S-1-5-32-545 (BUILTIN\Users)
GroupSID= S-1-5-4 (NT AUTHORITY\INTERACTIVE)
GroupSID= S-1-5-11 (NT AUTHORITY\Authenticated Users)
GroupSID= S-1-2-0 (LOCAL)

Well, write a clone of who would be fun. Any volunteer?

[Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.]

Tags:       



Monday, January 16, 2006

Combination Rights, Inheritance and Propagation Settings of File System Access Rules

A more complexed example of combination rights, inheritance and propagation settings of access rules for directory.

Yesterday, I happened to find a code example of manipulating ACLs for .NET framework 1.0: ACLs in .NET: A C# library containing wrapper classes for ACL, ACE, Security descriptors, Security Attributes, Access tokens, etc. It is so complicated to working on platform invokation. As you can see from my previous blog entry Play with ACL in MSH, Play with ACL in MSH (continued) and /\/\o\/\/'s blog entry Adding a Simple AccesRule to a file ACL in MSH, with  .NET 2.0 things getting much easier. Today I am going to dig a little deeper and talk about more  complex example.

1. We have to deal with FileSystemRights enumeration when creating a new FileSystemAccessRule object. We can see from following that FileSystemRights contain 23 names:
[system.enum]::getnames([System.Security.AccessControl.FileSystemRights])
ListDirectory
ReadData
WriteData
CreateFiles
CreateDirectories
AppendData
ReadExtendedAttributes
WriteExtendedAttributes
Traverse
ExecuteFile
DeleteSubdirectoriesAndFiles
ReadAttributes
WriteAttributes
Write
Delete
ReadPermissions
Read
ReadAndExecute
Modify
ChangePermissions
TakeOwnership
Synchronize
FullControl

FileSystemRights enumeration has a FlagsAttribute attribute that allows a bitwise combination of its member values. In MSH, "-bor" is used as "Bitwise OR" Operator. To better understand that, we can find from following example that "Read" actually means ReadData | ReadExtendedAttributes | ReadAttributes |ReadPermissions.
[int]([System.Security.AccessControl.FileSystemRights]::Read)
131209
[System.Security.AccessControl.FileSystemRights]::ReadData `
-bor [System.Security.AccessControl.FileSystemRights]::ReadExtendedAttributes `
-bor [System.Security.AccessControl.FileSystemRights]::ReadAttributes `
-bor [System.Security.AccessControl.FileSystemRights]::ReadPermissions
131209

Added on 2006-01-17 12:27
Marcel Comment:"A comma separated list of values cast can be cast to a flags enum."
[System.Security.AccessControl.FileSystemRights] "ReadData, ReadExtendedAttributes, ReadAttributes, ReadPermissions"

Will do same thing!

So it is easier to use the combination values such as FullControl, Read and Write, rather than specifying each component value separately. But we still can build a custumized value such as "Read OR Write" as below.
$Rights= [System.Security.AccessControl.FileSystemRights]::Read `
-bor [System.Security.AccessControl.FileSystemRights]::Write
2. All of our previous examples were simple because we never deal with inheritance and propagation settings. If a directroy contain both files and child directory, things get more compicated. Every access rule is either explicit or inherited: inherited rules come from a parent container while explicit rules are added by user later on. So you can only manipulate its explicit rules.
There are two inheritance flags: container inherit (CI), object inherit (OI) and None.
There are two propagation flags: inherit only (IO), no-propagate inherit (NP) and None.
$Inherit=[System.Security.AccessControl.InheritanceFlags]::ContainerInherit `
        -bor [System.Security.AccessControl.InheritanceFlags]::ObjectInherit
$Prop=[System.Security.AccessControl.PropagationFlags]::InheritOnly
Now we can construct our access rule and set it to a directory:
# set AccessControlType : Allow / Deny
$Access=[System.Security.AccessControl.AccessControlType]::Allow
# create new access rule
$AccessRule = new-object System.Security.AccessControl.FileSystemAccessRule `
("testac",$Rights,$Inherit,$Prop,$Access)
# validate access rule
$Sid = $AccessRule.IdentityReference.Translate`
([System.Security.Principal.securityidentifier])
$ACL=get-acl D:\msh\tmp
$ACL.AddAccessRule($AccessRule)
set-acl -AclObject $ACL -Path D:\msh\tmp

 3. What if you do NOT want to inherit access rules from you parents?
$ACL=get-acl D:\msh\tmp
$ACL.SetAccessRuleProtection(
           # changes from parent won't propagate
           $true,
           # do not keep current inheritance settings
           $false );
set-acl -AclObject $ACL -Path D:\msh\tmp
Reference: Manage Access to Windows Objects with ACLs and the .NET Framework

[Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.]

Tags:       



Friday, January 13, 2006

Use Search-Entrez Cmdlet and Format Results

In my previous blog entry Author a Monad Cmdlet as Web Service Client, I created a cmdlet Search-Entrez. Let's see what we can do with this cmdlet.
get-command search-entrez | format-list
Name : search-entrez
CommandType : Cmdlet
Definition : search-entrez [-Database] String [-Keywords] String [[-MaxRecor
d] String] [[-Email] String] [[-Field] String] [[-RelativeDate]
String] [[-MinimumDate] String] [[-MaximumDate] String] [[-Dat
eType] String] [-Verbose] [-Debug] [-ErrorAction ActionPreferen
ce] [-ErrorVariable String] [-OutVariable String] [-OutBuffer I
nt32] [-WhatIf] [-Confirm]

Path :
AssemblyInfo :
DLL : D:\msh\Entrez-mshsnapin.dll
HelpFile : Entrez-mshsnapin.dll-Help.xml
ParameterSets : {__AllParameterSets}
Type : Entrez.SearchEntrezCmd
Verb : search
Noun : entrez

Database: the Entrez database name (can be pubmed, protein, nucleotide, nuccore, nucgss, nucest, structure, genome, books, cancerchromosomes, cdd, domains, gene, genomeprj, gensat, geo, gds, homologene, journals, mesh, ncbisearch, nlmcatalog, omia, omim, pmc, popset, probe, pcassay, pccompound, pcsubstance, snp, taxonomy, unigene, unists)

Keywords: the search strategy. All words should be URL encoded (that is to say blank should be +). Can be keywords plus "AND/OR/NOT"

Other parameter is not mandatory.
Using MaximumRecord would limit numbers of results returned to you.
Using Email parameter would help NCBI server inform you if something went wrong.

$resultSummary=search-entrez pubmed "cancer+T+cell" -MaxRecord 10 -Email test@test.com -verbose
VERBOSE: Searching Entrez database...
Database: pubmed
Keywords: cancer+T+cell
VERBOSE: Creating Entrez WebService...
VERBOSE: Submit search...
VERBOSE: Number of results item found:51521
VERBOSE: Getting results summary...
VERBOSE: Number of item retrieved:10
VERBOSE: Write results to pipline...

Because I was too lazy to write code for results parsing, I just emitted an eUtils.eSummaryResultType object to monad pipline, which make search-Entrez cmdlet return a non-human-readable output.
$resultSummary | format-list
ERROR :
DocSum : {16408214, 16407851, 16406172, 16404742, 16404738, 16404427, 16403911, 16403282, 16401550, 16399573}

Where ERROR is a string object for error and Docsum is a collection of DocSumType objects.
public class DocSumType {
private string idField;
private ItemType[] itemField;
public string Id {
get {return this.idField;}
set {this.idField = value;}}
public ItemType[] Item {
get {return this.itemField;}
set {this.itemField = value;}}
}
To make things even more complicated, the DocSumType.ItemType is a collection of NESTED ItemType object. As you can see ItemType.Items is also a collection of ItemType objects.
public class ItemType {
private ItemType[] itemsField;
private string[] textField;
private string nameField;
private ItemTypeType typeField;
public ItemType[] Items {
get {return this.itemsField;}
set {this.itemsField = value;}}
public string[] Text {
get {return this.textField;}
set {this.textField = value;}}
public string Name {
get {return this.nameField;}
set {this.nameField = value;}}
public ItemTypeType Type {
get {return this.typeField;}
set {this.typeField = value;}}
}
The good news is that they seem to only nest TWO levels deep for pubmed results. So I write a script to format results.
# Format-eSummary.msh
# Script to format (pubmed) results from Search-Entrez cmdlet
#requires -MshSnapIn EntrezSnapin
param
(
$Summary =$(throw "Please specify an eUtils.eSummaryResultType object to parise.")
)
if ($Summary.DocSum.Length -eq 0)
{
"No hits found!"
return 1
}
foreach ($sum in $Summary.DocSum)
{
"Primary IDs:" + $sum.Id
foreach ($Item in $sum.Item)
{
$Item.Name + ": " + $Item.Text
if ($Item.Items)
{
foreach($ChildItem in $Item.Items)
{
"`t" + $ChildItem.Name + ": "+ $ChildItem.Text
}
}
} "====================================================="
}
return 0

.\Format-eSummary.msh $resultSummary

Primary IDs:16408214
PubDate: 2006 Jan 12
EPubDate: 2006 Jan 12
Source: Cancer Immunol Immunother
AuthorList:
Author: Prell RA
Author: Gearin L
Author: Simmons A
Author: Vanroey M
Author: Jooss K
Title: The anti-tumor efficacy of a GM-CSF-secreting tumor cell vaccine is not
inhibited by docetaxel administration.
Volume:
Issue:
Pages: 1-9
LangList:
Lang: English
NlmUniqueID: 8605732
ISSN: 0340-7004
ESSN: 1432-0851
PubTypeList:
PubType: Journal Article
RecordStatus: PubMed - as supplied by publisher
PubStatus: aheadofprint
ArticleIds:
doi: 10.1007/s00262-005-0116-4
pubmed: 16408214
DOI: 10.1007/s00262-005-0116-4
History:
received: 2005/11/08 00:00
accepted: 2005/12/15 00:00
aheadofprint: 2006/01/12 00:00
pubmed: 2006/01/13 09:00
medline: 2006/01/13 09:00
References:
HasAbstract: 1
PmcRefCount: 0
FullJournalName: Cancer immunology, immunotherapy : CII.
SO: 2006 Jan 12;:1-9
=====================================================
Primary IDs:16407851
PubDate: 2006 Jan 9
EPubDate: 2006 Jan 9
Source: Oncogene
......

Tags:    



Thursday, January 12, 2006

Author a Monad Cmdlet as Web Service Client

Steps to author a cmdlet, Search-Entrez, which works as NCBI eUtils web service client to build your own Entrez data pipeline.

For those who don't use Entrez:  Entrez is the integrated, text-based search and retrieval system used at NCBI for the major databases, including PubMed, Nucleotide and Protein Sequences, Protein Structures, Complete Genomes, Taxonomy, and others. If you were a biologist, you probably use Entrez everyday. The graphic below for a breif view of Entrez integration.

Usually general user will access Entrez by its web form interface. For data mining NCBI made a utility called: eUtils, which provide a URL tool as well as a SOAP interface. The URL tool requires to construct a customized search URL and returns results as XML. To save some time,  I decided to use  SOAP  interface (version 1.3a). More help on eUtils utility can be found here.  Information about SOAP interface can be  find here.

eUtils have contain several tools :  We will use ESearch and ESummary this time. Now let's start:
1. Create a "Class Libaray" in Visual C# Express.
2. Project -> Add Reference -> System.Management.Automation
3. Project -> Add Web Reference ->
http://eutils.ncbi.nlm.nih.gov/entrez/eutils/soap/eutils_lite.wsdl (without EFech tool) -> Go -> Change Web Refernece name to "eUtils"
4. Create new class derived from MshSnapin object.
5. Create new class derived from Cmdlet object.
6. Build project to EntrezSnapin.dll.
7. Install mshsnapin using .NET SDK installutils.exe tool.
set-alias installutil $env:windir\Microsoft.NET\Framework\v2.0.50727\installutil
installutil EntrezSnapin.dll
8. Load mshsnapin using add-mshsnapin cmdlet
get-mshsnapin -reg
add-mshsnapin EntrezSnapin
9. Now you can enjoy powerful Entrez search tool under msh prompt.
C# Code:
using System;
using System.ComponentModel;
using System.Management.Automation;
using System.Collections;
namespace Entrez
{
    /// <summary> This class defines the properties of a snapin</summary>
    [RunInstaller(true)]
    public class EntrezSnapin : MshSnapIn
    {
        /// <summary>Creates an instance of DemonSnapin class.</summary>
        public EntrezSnapin() : base()
        {
        }
        ///<summary>The snapin name which is used for registration</summary>
        public override string Name
        { get
            { return "EntrezSnapin";
            }
        }
        /// <summary>Gets vendor of the snapin.</summary>
        public override string Vendor
        { get
            { return "http://mshforfun.blogspot.com";
            }
        }
        /// <summary>Gets description of the snapin. </summary>
        public override string Description
        { get
            { return "Cmdlets to build your own NCBI Entrez Data pipeline";
            }
        }       
    }
    /// <summary>
    /// Submit search to entrez database and return results IDs
    /// </summary>
    [Cmdlet("search", "entrez", SupportsShouldProcess = true)]
    public class SearchEntrezCmd : Cmdlet
    {
        #region Parameters
        private string db="pubmed";
        /// <summary>Entrez Database</summary>
        [Parameter(Mandatory=true, Position=0)]
        public string Database
        {
            get { return db; }
            set { db = value; }
        }
        private string term;
        /// <summary>search terms or phrases with or without Boolean operators</summary>
        [Parameter(Mandatory = true, Position = 1)]
        public string Keywords
        {
            get { return term; }
            set { term = value; }
        }
        private string retmax = "50";
        /// <summary>Maximum number of records to return</summary>
        [Parameter(Position = 2)]
        public string MaxRecord
        {
            get { return retmax; }
            set { retmax = value; }
        }
        private string email = "";
        /// <summary>To identify your search results history on server</summary>
        [Parameter(Position = 3)]
        public string Email
        {
            get { return email; }
            set { email = value; }
        }
        private string field = "";
        /// <summary>specific search field for pubmed database</summary>
        [Parameter(Position = 4)]
        public string Field
        {
            get { return field; }
            set { field = value; }
        }
        private string reldate = "";
        /// <summary>Limit items a number of days immediately preceding today's date</summary>
        [Parameter(Position = 5)]
        public string RelativeDate
        {
            get { return reldate; }
            set { reldate = value; }
        }
        private string mindate = "";
        /// <summary>Lower bounded of two specific dates</summary>
        [Parameter(Position = 6)]
        public string MinimumDate
        {
            get { return mindate; }
            set { mindate = value; }
        }
        private string maxdate = "";
        /// <summary>Lower bounded of two specific dates</summary>
        [Parameter(Position = 7)]
        public string MaximumDate
        {
            get { return maxdate; }
            set { maxdate = value; }
        }
        private string datetype = "";
        /// <summary>Limit dates to a specific date field based on database</summary>
        [Parameter(Position = 8)]
        public string DateType
        {
            get { return datetype; }
            set { datetype = value; }
        }
        #endregion

        private string usehistory = "y";
        private string tool = "Monad_Entrez_Client";
        private string retstart = "0";
        private string rettype = "uilist";
        private string sort = "";
        /// <summary>
        /// Communicating purpose only
        /// </summary>
        protected override void BeginProcessing()
        {
            WriteVerbose("Searching Entrez database...\r\nDatabase: " + db + "\r\nKeywords: " + term);
        }
        /// <summary>
        /// Get Entrez search results
        /// </summary>
        protected override void ProcessRecord()
        {
            if (ShouldProcess("Searching Entrez database...\r\nDatabase: " + db + "\r\nKeywords: " + term))
            {
                try
                {
                    WriteVerbose("Creating Entrez WebService...");
                    eUtils.eUtilsService serv = new eUtils.eUtilsService();
                    WriteDebug("WebService:" + serv.ToString());
                    WriteVerbose("Submit search...");
                    // call NCBI ESearch utility
                    // NOTE: search term should be URL encoded
                    eUtils.eSearchResultType Search_Results = serv.run_eSearch_MS(db, term, "", "", usehistory, tool, email, field, reldate, mindate, maxdate, datetype, retstart, retmax, rettype, sort );
                    WriteDebug("Search Results:" + Search_Results.ToString());
                    if (Search_Results.ERROR != null)
                    {
                        ThrowTerminatingError(new ErrorRecord(new Exception("web service method error"), "eUtils.run_eSearch_MS", ErrorCategory.InvalidResult, Search_Results));
                    }
                    WriteVerbose("Number of results item found:" + Search_Results.Count);
                    WriteVerbose("Getting results summary...");
                    // call NCBI ESummary utility
                    // NOTE: search term should be URL encoded
                    eUtils.eSummaryResultType Summary_Results = serv.run_eSummary_MS( db, "", Search_Results.WebEnv, Search_Results.QueryKey, Search_Results.RetStart, Search_Results.RetMax,  tool, email );
                    WriteDebug("Results summary:" + Summary_Results.ToString());
                    if (Summary_Results.ERROR != null)
                    {
                        ThrowTerminatingError(new ErrorRecord(new Exception("web service method error"), "eUtils.run_eSummary_MS", ErrorCategory.InvalidResult, Summary_Results));
                    }
                    WriteVerbose("Number of item retrieved:" + Summary_Results.DocSum.Length);
                    WriteVerbose("Write results to pipline...");
                    // results output
                    WriteObject(Summary_Results);
                }
                catch (Exception e)
                {
                    ThrowTerminatingError(new ErrorRecord(e, "eUtils", ErrorCategory.ResourceUnavailable, db+term));
                }
            }
        }
    }
}


[Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.]

Tags:       



Monday, January 09, 2006

Bring Statistical Analysis Power to MSH: Hosting R Environment

Quote from /\/\o\/\/ blog entry Hosting Iron python in MSH: "Nice thing about Monad that it's easy to host other Languages inline." Well, since /\/\o\/\/ did VB.net, Monad team blog did C# and those japanese guy did python. I would like to something a biologist should do: Hosting R Environment in MSH.

R is an integrated suite of software facilities for data manipulation, calculation and graphical display. It consists of a language plus a run-time environment with graphics, a debugger, access to certain system functions, and the ability to run programs stored in script files. R language is an interpreted computer language derived from S language. Scientist use R mostly as a statistical analysis tool. You can download a copy of R from R-project home page (under GNU license).

My last project involve R is a gene expression profile analysis from microarray experiment two years ago. If you were a computer geek, it will take you less than 30min to learn to use R environment because it is object-oriented and synax similar to C.

Monad can can interact with other program using COM-based technologies. For example:
1. From /\/\o\/\/ blog: Monad Really Does Rock
2. From Monad team blog: Check spelling script

In order to use R language interpreter in MSH, we need another R addon: R-DCOM, which works with Rproxy.dll (in the R distribution) and R.dll to support transfer of data to and from R and remote execution of R commands, as well as embedding of an R graphics window.

After insatll R and r-DCOM, we can enjoy the power of R under MSH prompt:

# Create a new com object for R
$RCom = new-object -com StatConnectorSrv.StatConnector

# Call Init method to load R environment
$RCom.Init("R")

# Check out available methods
$Rcom |gm

TypeName: System.__ComObject#{18c8b660-81a2-11d3-9254-00e09812f727}

Name MemberType Definition
---- ---------- ----------
AddGraphicsDevice Method void AddGraphicsDevice (string, ISGFX)
Close Method void Close ()
Evaluate Method Variant Evaluate (string)
EvaluateNoReturn Method void EvaluateNoReturn (string)
GetConnectorInformation Method string GetConnectorInformation (Informa...
GetErrorId Method int GetErrorId ()
GetErrorText Method string GetErrorText ()
GetInterpreterInformation Method string GetInterpreterInformation (Infor...
GetServerInformation Method string GetServerInformation (Informatio...
GetSupportedTypes Method void GetSupportedTypes (int)
GetSymbol Method Variant GetSymbol (string)
Init Method void Init (string)
RemoveGraphicsDevice Method void RemoveGraphicsDevice (string)
SetCharacterOutputDevice Method void SetCharacterOutputDevice (IStatCon...
SetErrorDevice Method void SetErrorDevice (IStatConnectorChar...
SetSymbol Method void SetSymbol (string, Variant)
SetTracingDevice Method void SetTracingDevice (IStatConnectorCh...
SetUserInterfaceAgent Method void SetUserInterfaceAgent (IStatConnec...

# Send expression to R interpreter
# where c() is a function to assign a "vector" Variant to x
# remember R language is case senitive
$Rcom.EvaluateNoReturn ("x <- c(79.98, 80.04, 80.02, 80.04, 80.03, 80.03, 80.04, 79.97, 80.05, 80.03, 80.02, 80.00, 80.02)")
$Rcom.EvaluateNoReturn ("y <-c(80.02, 79.94, 79.98, 79.97, 79.97, 80.03, 79.95, 79.97)")

# use R graphic device to make boxplot
$Rcom.EvaluateNoReturn ("boxplot(x, y)")


# Student t test: two variant; two sided; unpaired
$Rcom.Evaluate("t.test(x, y, alternative = c(`"two.sided`"))")



3.24986738055522 #t
12.0271084945182 #delta-f
0.00693932661444795 #P-value (if less than 0.05, means statitical significant)
0.0138552637266242 #lower 95 percent confidence interval
80.0207692307692 #average of x
0 #alternative hypothesis: true difference in means is not equal to 0
two.sided
Welch Two Sample t-test
x and y
# Dispose R Environment
$Rcom.Close()

Have fun!

[Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.]

Tags:       



Sunday, January 08, 2006

GUI version of NCBI Blastn(nr) MSH script

An NCBI Blastn (using nr database) client MSH script with winform GUI. See NCBI Blastn under MSH command line for a introduction of NCBI Blastn program.

Although personally I like command line interface, there are always some users prefer GUI. Well, since monad can use System.Windows.Forms.form, it can create comman winform GUI which is similar to what tk/tcl can do.

One of the big advantage of monad is that script block can be used a event handler.

Another thing need to mention is that monad use grave-accent(`) but not "\" for escape sequences. To get more help on escape character using command:
help about_escape_character
Because NCBI Blast server running unix like OS, so the returning results using \n but not \r\n for a new line. We have to replace those \n with \r\n to get a proper view in textbox control.



# Blastn-GUI.msh
# ===========================================================================
#
# This code is for test purposes only. Use it at your own risk.
#
# Please do not submit or retrieve more than one request every two seconds.
#
# Results will be kept at NCBI for 24 hours. For best batch performance,
# It is recommend that you submit requests after 2000 EST (0100 GMT) and
# retrieve results before 0500 EST (1000 GMT).
#
# by tony 2006 http://mshforfun.blogspot.com/
# ===========================================================================
[void] [Reflection.Assembly]::Load( `
"System.Windows.Forms, Version=2.0.0.0, Culture=neutral, `
PublicKeyToken=b77a5c561934e089")
$script:form = new-object System.Windows.Forms.form
$Panel = new-object System.Windows.Forms.Panel
$Label = new-object System.Windows.Forms.Label
$Query = new-object System.Windows.Forms.TextBox
$Submit = new-object System.Windows.Forms.Button
$script:Results = new-object System.Windows.Forms.TextBox
$script:Status = new-object System.Windows.Forms.TextBox

function SubmitQuery([String]$Sequence)
{
 if ($Sequence -match "[^ATGCatgcNn]")
 {
    $Status.Text += "Error 1: Invalid charactors in query sequence! Only A/T/G/C/N can be used!`r`n`r`n"
    $Status.Refresh()
    $Status.ScrollToCaret()
    return
 }
 
 $Status.Text += "`r`n==================================================`r`n"
 $Status.Text += (get-date).ToString("MM-dd-yyyy HH:mm") + ": Submiting sequence...`r`n"
 $Status.Refresh()
 $Status.ScrollToCaret()

 $uri="http://www.ncbi.nlm.nih.gov/blast/Blast.cgi?CMD=Put&PROGRAM=blastn&DATABASE=nr&QUERY=" + $Sequence
 $BlastClient = new-object System.Net.WebClient
 $pagecontent = $BlastClient.DownloadString($uri);
 if ($pagecontent -match "   RID = (.*)")
 {
   $RID=$Matches[1]
   $Status.Text += "RID =" + $RID + "`r`n"
   $Status.Refresh()
   $Status.ScrollToCaret()
  }

 if ($pagecontent -match "   RTOE = (.*)")
 {
  $TimeToComplete= $Matches[1]
  $Status.Text += "Estimated Time to finish searching: " + $TimeToComplete + " seconds`r`nWaiting...`r`n`r`n"
  $Status.Refresh()
  $Status.ScrollToCaret()
 }

 Start-sleep $TimeToComplete

 While ($true)
 {
  
   $uri= "http://www.ncbi.nlm.nih.gov/blast/Blast.cgi?CMD=Get&FORMAT_OBJECT=SearchInfo&RID=" + $RID   
   $pagecontent = $BlastClient.DownloadString($uri);
   if ($pagecontent -match "Status=WAITING")
   {
    $Status.Text += (get-date).ToString("MM-dd-yyyy HH:mm") + ": Search not finished yet, waiting... `r`n"
    $Status.Refresh()
    $Status.ScrollToCaret()
    Start-sleep 5
    continue
   }
   if ($pagecontent -match "Status=FAILED")
   {
     $Status.Text += (get-date).ToString("MM-dd-yyyy HH:mm") + ": Error 2 -- Search failed!`r`n`r`n"
     $Status.Refresh()
     return
   }
   if ($pagecontent -match "Status=UNKNOWN")
   {
     $Status.Text += (get-date).ToString("MM-dd-yyyy HH:mm") + ": Error 3-- Search expired!`r`n`r`n"
     $Status.Refresh()
     return
   }
   if ($pagecontent -match "Status=READY")
   { 
      if ($pagecontent -match "ThereAreHits=yes")
      {
         $Status.Text += (get-date).ToString("MM-dd-yyyy HH:mm") + ": Search complete, retrieving results...`r`n`r`n"
     $Status.Refresh()
     $Status.ScrollToCaret()
     break
      }
      else
      {
        $Status.Text += (get-date).ToString("MM-dd-yyyy HH:mm") + ": Error 4-- No hits found!`r`n`r`n"
    $Status.Refresh()
        return
      }
   }
   $Status.Text += (get-date).ToString("MM-dd-yyyy HH:mm") + ": Error 5-- Unknown error! `r`n`r`n"
   $Status.Refresh()
   return
}
$uri= "http://www.ncbi.nlm.nih.gov/blast/Blast.cgi?CMD=Get&RID=" + $RID + "&ALIGNMENTS=500&ALIGNMENT_VIEW=QueryAnchored&FORMATOBJECT=Alignment&FORMAT_TYPE=TEXT"
$Results.Text = $BlastClient.DownloadString($uri).Replace("`n","`r`n");
return
}

$form.text = "NCBI Blastn(nr) GUI"
$form.Size =  "800,600"

$Panel.Size = "794, 32"
$Panel.Location = "0, 0"

$Label.Text = "Query:"
$Label.Location = "10, 8"
$Label.Size = "80, 32"
$Panel.Controls.Add($Label)

$Query.Location = "100, 8"
$Query.Size = "500, 20"
$Panel.Controls.Add($Query)

$Submit.Location = "710, 8"
$Submit.Text = "Submit"
$Submit.Add_Click({SubmitQuery($Query.Text)})
$Panel.Controls.Add($Submit)

$form.Controls.Add($Panel)

$Results.Location = "0, 40"
$Results.Multiline = $True
$Results.Size = "790, 400"
$Results.ScrollBars = "Vertical"
$Results.ReadOnly = $true
$form.Controls.Add($Results)

$Status.Location = "0, 440"
$Status.Multiline = $True
$Status.Size = "790, 100"
$Status.ScrollBars = "Vertical"
$Status.ReadOnly = $true
$form.Controls.Add($Status)

$form.showdialog() 


[Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.]

Tags:       



Tuesday, January 03, 2006

Play with ACL in MSH (continued)

/\/\o\/\/ kindly replied my blog entry “Play with ACL in MSH”. In his blog entry “Adding a Simple AccesRule to a file ACL in MSH”, he found a shortcut to create an instance of “System.Security.AccessControl.FileSystemAccessRule”. Great job! But things can get even better!

1. You want to change a accessrule but not overwrite it, so AddAccessRule() method is better than SetAccessRule() method. If you want to grant a FullControl privilege to exact same user, they are the same. What if you want to apply a more complex privilege? For example: Read + Write nut not Delete.

2. get-acl cmdlet return different object:
For a file, it will return “System.Security.AccessControl.FileSecurity”;
For a directory, it will return “System.Security.AccessControl.DirectorySecurity”.
Luckily enough, both object have AddAccessRule() and RemoveAccessRule() methods. And Even better, both methods take a “System.Security.AccessControl.FileSystemAccessRule” as parameter. So we can set Access control of a file or directory in one simple script.



# AddRemove-AccessRule.MSH
# Add or remove simple access rule to a file/directory
# using text parameters
#
# original writen by /\/\o\/\/ 2006
# http://mow001.blogspot.com
#
# modified by tony 2006
# http://mshforfun.blogspot.com
#
#Usage AddRemove-Acl FileOrDirectory (Action) user Rights (Access)
# Action: Add / Remove
# Rights: ListDirectory / ReadData / WriteData / CreateFiles /
# CreateDirectories / AppendData / ReadExtendedAttributes /
# WriteExtendedAttributes / Traverse / ExecuteFile /
# DeleteSubdirectoriesAndFiles / ReadAttributes / WriteAttributes/ Write /
# Delete / ReadPermissions / Read / ReadAndExecute / Modify /
# ChangePermissions / TakeOwnership / Synchronize / FullControl
# Access: Allow / Deny

Param (
$FileDir,
$User,
$Action = "Add",
[System.Security.AccessControl.FileSystemRights] $Rights,
[System.Security.AccessControl.AccessControlType] $Access = "Allow"
)


trap{Break}

$AccessControl = get-acl $FileDir

$AccessRule = new-object System.Security.AccessControl.FileSystemAccessRule($User,$Rights,$Access)

# check if given user is Valid, this will break function if not so.
$Sid = $AccessRule.IdentityReference.Translate([System.Security.Principal.securityidentifier])

resolve-path $FileDir

"=============================================================="
"Before changes"
$AccessControl.AccessToString

if ($Action.ToUpper() -eq "ADD") {$AccessControl.AddAccessRule($AccessRule)}
elseif ($Action.ToUpper() -eq "REMOVE") {$AccessControl.RemoveAccessRule($AccessRule)}

set-acl -aclobject $AccessControl -path $FileDir

"=============================================================="
"After " + $Action + " access rule: " + "User-"+ $User + " Rights-" + $Rights + " Access-" + $Access
(get-acl $FileDir).AccessToString



[Edit: Monad has now been renamed to Windows PowerShell. This script or discussion may require slight adjustments before it applies directly to newer builds.]

Tags:       



Working with SQL server in monad using pre-compiled .NET Class Library (3)

Now the usual routine operation:

Add a plasmid
Edit a plasmid

Why there is no “Delete plasmid” operation?

Because Biologists Never, Never, Ever lose their plasmids!


1. Add following code to our PlasmidView.DLL:


namespace PlasmidView

public class SQLProvider
{
public static PlasmidFull PlasmidFull_ByPlasmidID (int plasmidid)
{… }

public static void Plasmid_Add (PlasmidFull PlasmidToAdd)
{… }
public static void Plasmid_Edit (PlasmidFull PlasmidToEdit)
{…}

public static string Enzyme_ByEnzymeID (int enzymeID)
{…}
public static string BacResistanceType_ByTypeID (int TypeID)
{…}
public static string MamResistanceType_ByTypeID (int TypeID)
{…}
public static string InsertType_ByInsertTypeID (int insertTypeID)
{…}
}
public class PlasmidFull : PlasmidCore
{…}
}


2. Get a Plasmid by PlasmidID

[void][System.Reflection.Assembly]::LoadFile("D:\MSH\PlasmidView.dll")
$Plasmid= [PlasmidView.SQLProvider]::PlasmidFull_ByPlasmidID (10)
$Plasmid


BacResistance : 1
MamResistance : 2
HasGlycerolStock : False
InsertDescription : IL-17R full length receptor
InsertLength : 2451
InsertTypeID : 1
InsertType : Human
LeftEnzymeID : 14
LeftEnzyme : BamHI
RightEnzymeID : 62
RigthEnzyme : NcoI
IsBluntLigation : False
IsSequenced : True
Comments :
FullSeq :
InsertSeq :
PlasmidID : 10
BoxID : B
BoxPosition : 1
PlasmidName : IL-17R-FL-HA
DateCreated : 10/30/2005 9:18:18 PM
UserID : 1
UserCreated : me
PlasmidType : Cytokine Receptor
PlasmidTypeID : 3
ParentPlasmidID : 9
ParentPlasmid : pCMV4 HA Neo

3. Edit this plasmid entry

$Plasmid.PlasmidName = “mouse IL-17R-FL-HA”
$Plasmid.InsertTypeID = 2
[PlasmidView.SQLProvider]::Plasmid_Edit($Plasmid)
$Plasmid= [PlasmidView.SQLProvider]::PlasmidFull_ByPlasmidID (10)
$Plasmid


BacResistance : 1
MamResistance : 2
HasGlycerolStock : False
InsertDescription : IL-17R full length receptor
InsertLength : 2451
InsertTypeID : 2
InsertType : Mouse
LeftEnzymeID : 14
LeftEnzyme : BamHI
RightEnzymeID : 62
RigthEnzyme : NcoI
IsBluntLigation : False
IsSequenced : True
Comments :
FullSeq :
InsertSeq :
PlasmidID : 10
BoxID : B
BoxPosition : 1
PlasmidName : mouse IL-17R-FL-HA
DateCreated : 10/30/2005 9:18:18 PM
UserID : 1
UserCreated : me
PlasmidType : Cytokine Receptor
PlasmidTypeID : 3
ParentPlasmidID : 9
ParentPlasmid : pCMV4 HA Neo
4. Add a plasmid entry

$Plasmid= new-object PlasmidView.PlasmidFull
$Plasmid.BacResistance = 1
$Plasmid.MamResistance = 2
$Plasmid.HasGlycerolStock = $False
$Plasmid.InsertDescription = "truncated IL-17R receptor"
$Plasmid.InsertLength = 1851
$Plasmid.InsertTypeID = 2
$Plasmid.LeftEnzymeID = 14
$Plasmid.RightEnzymeID = 62
$Plasmid.IsBluntLigation = $False
$Plasmid.IsSequenced = $True
$Plasmid.BoxID = "B"
$Plasmid.BoxPosition = 90
$Plasmid.PlasmidName = "truncated mouse IL-17R-FL-HA"
$Plasmid.DateCreated = get-date
$Plasmid.UserID = 1
$Plasmid.PlasmidTypeID = 3
$Plasmid.ParentPlasmidID = 9

$Plasmid
$Plasmid= [PlasmidView.SQLProvider]::Plasmid_Add($Plasmid)
[PlasmidView.SQLProvider]::Plasmid_All() where-object {$_.PlasmidName
-like "*truncated mouse IL-17R-FL-HA*"}


PlasmidID : 22
BoxID : B
BoxPosition : 90
PlasmidName : truncated mouse IL-17R-FL-HA
DateCreated : 1/3/2006 12:09:52 AM
UserID : 1
UserCreated : me
PlasmidType : Cytokine Receptor
PlasmidTypeID : 3
ParentPlasmidID : 9
ParentPlasmid : pCMV4 HA Neo

Conclusion:
1. One of the advantages of using monad is that it is fully integrated with .Net frameworks. Although MSH does not have class definition machinery right now, we can easily construct a customized class in C# and use it in monad.

2. Pre-compiled class library will greatly simplify monad script. Even a new user can be trained to work with fairly complex administration jobs.

3. Security should always be in mind! Expose crucial objects or methods to unauthorized user may cause disastrous effect to system.

Tags:    



Sunday, January 01, 2006

Working with SQL server in monad using pre-compiled .NET Class Library (2)

Now we can do something fun.

1. Add following code to our PlasmidView.DLL


using System.Collections;
namespace PlasmidView
{
     public class SQLProvider
     {

// return ArrayList of “PlasmidCore” objects of all plasmid information
public static ArrayList Plasmid_All ()
{...}

// return a PlasmidCore object
public static PlasmidCore PlasmidCore_ByPlasmidID (int plasmidid)
{...}

// return User objects
public static User User_ByUserID (int userid)
{...}

// return Plasmid Type (String)
public static string PlasmidType_ByPlasmidTypeID (int plasmidTypeID)
{...}

public class PlasmidCore
{... }

public class User
{... }
}

I omit most of C# code here

2. Try to get all plasmid informtion

[void][System.Reflection.Assembly]::LoadFile("D:\MSH\PlasmidView.dll")
[PlasmidView.SQLProvider]::Plasmid_All()

PlasmidID       : 1
BoxID           : A
BoxPosition     : 1
PlasmidName     : pCMV4 Hygro
DateCreated     : 10/30/2005 8:58:24 PM
UserID          : 1
UserCreated     : me
PlasmidType     : Backbone Vector
PlasmidTypeID   : 1
ParentPlasmidID : 0
ParentPlasmid   : None

PlasmidID       : 2
BoxID           : A
BoxPosition     : 2
PlasmidName     : pCMV4 Neo
DateCreated     : 10/30/2005 9:07:16 PM
UserID          : 1
UserCreated     : me
PlasmidType     : Backbone Vector
PlasmidTypeID   : 1
ParentPlasmidID : 0
ParentPlasmid   : None


3. Try to search plasmid with “hygro” in their names:

[PlasmidView.SQLProvider]::Plasmid_All()  where-object {$_.PlasmidName -like “*hygro*”} foreach-object {“============”; “ID:”+ $_.PlasmidID; “Name:” + $_.PlasmidName}

============
ID:1
Name:pCMV4 Hygro
============
ID:20
Name:TAg Hygro


Conclusion:
1. We can easily return a group of objects to monad using ArrayList. Unlike strong typed language (for example, C#) monad detects the base object of each Item in ArrayList. You do NOT have to cast each ArrayList Item to its original base object (PlasmidView.PlasmidCore) when quoting them in a pipline.

2. When database is small, using where-object cmdlet to do search is a good idea. Actually I even forgot I had a Plasmid_Search( ) method in my original C# code. But when database grew bigger, better use a Search function to return limited number of objects only from search results.

Tags: