Keith Hill's Blog News Feed 
Thursday, May 09, 2013  |  From Keith Hill's Blog

I have some older hardware running Windows 7 Media Center.  Normally we let the Media Center just go to sleep on its own but I’ve been concerned that it isn’t sleeping as much during there wee hours of the morning … Continue reading

Friday, April 05, 2013  |  From Keith Hill's Blog

If were following good security practices we run our Windows system with UAC enabled.  This means that if you forget to launch your PowerShell prompt as Administrator when you run a script that requires administrative privilege then that script will … Continue reading

Friday, January 11, 2013  |  From Keith Hill's Blog

You can download it here.

Sunday, September 16, 2012  |  From Keith Hill's Blog

Oisin and I have been busy prepping the PowerShell Community Extensions to support Windows PowerShell 3.0.  With this release, we are providing two packages.  There is a Pscx-2.1.0-RC.zip that is xcopy deployable just like PSCX 2.0.  Just remember to unblock … Continue reading

Friday, July 27, 2012  |  From Keith Hill's Blog

We’ve just released a beta of the PowerShell Community Extensions 3.0 which targets PowerShell 3.0 specifically.  This new version uses a WiX based installer.  We may look at providing an xcopy deployable ZIP file but we had so many users … Continue reading

Monday, April 30, 2012  |  From Keith Hill's Blog

PowerShell V3 now supports the ObsoleteAttribute for compiled cmdlets but unfortunately not advanced functions.  This is handy to let your users know that a binary cmdlet will be going away in a future release of your binary module. As we … Continue reading

Monday, March 05, 2012  |  From Keith Hill's Blog

One of the many new features in Windows PowerShell V3 is better support for alternate data streams (ADS) in NTFS files.  ADS allows an NTFS file to contain additional data that is not part of the “main” stream i.e. the … Continue reading

Monday, January 02, 2012  |  From Keith Hill's Blog

Within PowerShell it has always been easy to pass “simple” arguments to an EXE e.g.: C:\PS> ipconfig -all However passing arguments to certain exes can become surprising difficult when their command line parameter syntax is complex i.e. they require quotes … Continue reading

Monday, December 05, 2011  |  From Keith Hill's Blog

You can grab the bits from here. If you have V3 CTP1 installed, please uninstall it first or you can get your machine into a bad state. So far my favorite two features new to this drop are both in … Continue reading

Thursday, October 20, 2011  |  From Keith Hill's Blog

Windows PowerShell version 3 introduces a simplified syntax for the Where-Object and Foreach-Object cmdlets.  The simplified syntax shown below, eliminates the curly braces as well as the need for the special variable $_. C:\PS> Get-Process | Where PM -gt 100MB … Continue reading

Monday, September 19, 2011  |  From Keith Hill's Blog

I just uploaded beta 1 for the PowerShell Community Extensions version 2.1.  This beta drop adds better support for Windows PowerShell V3 that is in the Windows 8 Developer Preview.  There are a number of bug fixes in this drop: … Continue reading

Thursday, March 10, 2011  |  From Keith Hill's Blog

Testing out my first WordPress blog post after the switch from Windows Live Spaces (sniff, I will miss you) to WordPress.  Regarding the MVP Summit last week, I can’t really talk about much due to just about everything being NDA, NDA, … Continue reading

Tuesday, September 21, 2010  |  From Keith Hill's Blog


Occasionally folks want to be able to create an EXE from PoweShell.  PowerShell can’t do this by itself but this can be done with PowerShell script.  Essentially what you can do is create a simple console EXE program that embeds the script as a resource and the EXE, upon loading retrieves the script and throws it at a PowerShell runspace to execute.  Here’s the script for a feasibility test of doing this very thing.


Note that this script depends on Write-GZip from the PowerShell Community Extensions.


#requires -version 2.0
<#
.SYNOPSIS
    Creates an EXE wrapper from a PowerShell script by compressing the script and embedding into
    a newly generated assembly.
.DESCRIPTION
    Creates an EXE wrapper from a PowerShell script by compressing the script and embedding into
    a newly generated assembly.
.PARAMETER Path
    The path to the .
.PARAMETER LiteralPath
    Specifies a path to one or more locations. Unlike Path, the value of LiteralPath is used exactly as it
    is typed. No characters are interpreted as wildcards. If the path includes escape characters, enclose
    it in single quotation marks. Single quotation marks tell Windows PowerShell not to interpret any
    characters as escape sequences.
.PARAMETER OutputAssembly
    The name (including path) of the EXE to generate.
.PARAMETER IconPath
    The path to an optional icon to be embedded as the application icon for the EXE.
.EXAMPLE
    C:\PS> .\Make-PS1ExeWrapper.ps1 .\MyScript.ps1 .\MyScript.exe .\app.ico
    This creates an console application called MyScript.exe that internally hosts the PowerShell
    engine and runs the script specified by MyScript.ps1.  Optionally the file app.ico is
    embedded into the EXE as the application's icon.
.NOTES
    Author: Keith Hill
    Date:   Aug 7, 2010
    Issues: This implementation is more of a feasibility test and isn't fully functional.  It doesn't
            support an number of PSHostUserInterface members as well as a number of PSHostRawUserInterface
            members.  This approach also suffers from the same problem of running script "interactively"
            and not loading it from a file. That is, the entire script output is run through Out-Default
            and PowerShell gets confused.  It formats the first types it sees correctly but after that the
            formatting is off.  To correct this, you have to append | Out-Default where you script outputs
            to the host without using a Write-* cmdlet e.g.:
           
            MyScript.ps1:
            -------------------------------
            Get-Process svchost
            Get-Date | Out-Default
            Dir C:\  | Out-Default
            Dir c:\idontexist | Out-Default
            $DebugPreference = 'Continue'
            $VerbosePreference = 'Continue'
            Write-Host    "host"
            Write-Warning "warning"
            Write-Verbose "verbose"
            Write-Debug   "debug"
            Write-Error   "error"
#>
[CmdletBinding(DefaultParameterSetName="Path")]
param(
    [Parameter(Mandatory=$true, Position=0, ParameterSetName="Path",
               ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true,
               HelpMessage="Path to bitmap file")]
    [ValidateNotNullOrEmpty()]
    [string[]]
    $Path,
   
    [Alias("PSPath")]
    [Parameter(Mandatory=$true, Position=0, ParameterSetName="LiteralPath",
               ValueFromPipelineByPropertyName=$true,
               HelpMessage="Path to bitmap file")]
    [ValidateNotNullOrEmpty()]
    [string[]]
    $LiteralPath,


    [Parameter(Mandatory = $true, Position = 1)]
    [string]
    $OutputAssembly,
   
    [Parameter(Position = 2)]
    [string]
    $IconPath
)


Begin {
    Set-StrictMode -Version latest
   
    $src = @'
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;
using System.Reflection;
using System.Security;
using System.Text;
using System.Threading;


namespace PS1ToExeTemplate
{
    class Program
    {
        private static object _powerShellLock = new object();
        private static readonly Host _host = new Host();
        private static PowerShell _powerShellEngine;


        static void Main(string[] args)
        {
            Console.CancelKeyPress += Console_CancelKeyPress;
            Console.TreatControlCAsInput = false;


            string script = GetScript();
            RunScript(script, args, null);
        }


        private static string GetScript()
        {
            string script = String.Empty;


            Assembly assembly = Assembly.GetExecutingAssembly();
            using (Stream stream = assembly.GetManifestResourceStream("Resources.Script.ps1.gz"))
            {
                var gZipStream = new GZipStream(stream, CompressionMode.Decompress, true);
                var streamReader = new StreamReader(gZipStream);
                script = streamReader.ReadToEnd();
            }


            return script;
        }


        private static void RunScript(string script, string[] args, object input)
        {
            lock (_powerShellLock)
            {
                _powerShellEngine = PowerShell.Create();
            }


            try
            {
                _powerShellEngine.Runspace = RunspaceFactory.CreateRunspace(_host);
                _powerShellEngine.Runspace.Open();
                _powerShellEngine.AddScript(script);
                _powerShellEngine.AddCommand("Out-Default");
                _powerShellEngine.Commands.Commands[0].MergeMyResults(PipelineResultTypes.Error, PipelineResultTypes.Output);


                if (input != null)
                {
                    _powerShellEngine.Invoke(new[] { input });
                }
                else
                {
                    _powerShellEngine.Invoke();
                }
            }
            finally
            {
                lock (_powerShellLock)
                {
                    _powerShellEngine.Dispose();
                    _powerShellEngine = null;
                }
            }
        }


        private static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
        {
            try
            {
                lock (_powerShellLock)
                {
                    if (_powerShellEngine != null && _powerShellEngine.InvocationStateInfo.State == PSInvocationState.Running)
                    {
                        _powerShellEngine.Stop();
                    }
                }
                e.Cancel = true;
            }
            catch (Exception ex)
            {
                _host.UI.WriteErrorLine(ex.ToString());
            }
        }
    }


    class Host : PSHost
    {
        private PSHostUserInterface _psHostUserInterface = new HostUserInterface();


        public override void SetShouldExit(int exitCode)
        {
            Environment.Exit(exitCode);
        }


        public override void EnterNestedPrompt()
        {
            throw new NotImplementedException();
        }


        public override void ExitNestedPrompt()
        {
            throw new NotImplementedException();
        }


        public override void NotifyBeginApplication()
        {
        }


        public override void NotifyEndApplication()
        {
        }


        public override string Name
        {
            get { return "PSCX-PS1ToExeHost"; }
        }


        public override Version Version
        {
            get { return new Version(1, 0); }
        }


        public override Guid InstanceId
        {
            get { return new Guid("E4673B42-84B6-4C43-9589-95FAB8E00EB2"); }
        }


        public override PSHostUserInterface UI
        {
            get { return _psHostUserInterface; }
        }


        public override CultureInfo CurrentCulture
        {
            get { return Thread.CurrentThread.CurrentCulture; }
        }


        public override CultureInfo CurrentUICulture
        {
            get { return Thread.CurrentThread.CurrentUICulture; }
        }
    }


    class HostUserInterface : PSHostUserInterface, IHostUISupportsMultipleChoiceSelection
    {
        private PSHostRawUserInterface _psRawUserInterface = new HostRawUserInterface();


        public override PSHostRawUserInterface RawUI
        {
            get { return _psRawUserInterface; }
        }


        public override string ReadLine()
        {
            return Console.ReadLine();
        }


        public override SecureString ReadLineAsSecureString()
        {
            throw new NotImplementedException();
        }


        public override void Write(string value)
        {
            string output = value ?? "null";
            Console.Write(output);
        }


        public override void Write(ConsoleColor foregroundColor, ConsoleColor backgroundColor, string value)
        {
            string output = value ?? "null";
            var origFgColor = Console.ForegroundColor;
            var origBgColor = Console.BackgroundColor;
            Console.ForegroundColor = foregroundColor;
            Console.BackgroundColor = backgroundColor;
            Console.Write(output);
            Console.ForegroundColor = origFgColor;
            Console.BackgroundColor = origBgColor;
        }


        public override void WriteLine(string value)
        {
            string output = value ?? "null";
            Console.WriteLine(output);
        }


        public override void WriteErrorLine(string value)
        {
            string output = value ?? "null";
            var origFgColor = Console.ForegroundColor;
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine(output);
            Console.ForegroundColor = origFgColor;
        }


        public override void WriteDebugLine(string message)
        {
            WriteYellowAnnotatedLine(message, "DEBUG");
        }


        public override void WriteVerboseLine(string message)
        {
            WriteYellowAnnotatedLine(message, "VERBOSE");
        }


        public override void WriteWarningLine(string message)
        {
            WriteYellowAnnotatedLine(message, "WARNING");
        }


        private void WriteYellowAnnotatedLine(string message, string annotation)
        {
            string output = message ?? "null";
            var origFgColor = Console.ForegroundColor;
            var origBgColor = Console.BackgroundColor;
            Console.ForegroundColor = ConsoleColor.Yellow;
            Console.BackgroundColor = ConsoleColor.Black;
            WriteLine(String.Format(CultureInfo.CurrentCulture, "{0}: {1}", annotation, output));
            Console.ForegroundColor = origFgColor;
            Console.BackgroundColor = origBgColor;
        }


        public override void WriteProgress(long sourceId, ProgressRecord record)
        {
            throw new NotImplementedException();
        }


        public override Dictionary<string, PSObject> Prompt(string caption, string message, Collection<FieldDescription> descriptions)
        {
            if (String.IsNullOrEmpty(caption) && String.IsNullOrEmpty(message) && descriptions.Count > 0)
            {
                Console.Write(descriptions[0].Name + ": ");
            }
            else
            {
                this.Write(ConsoleColor.DarkCyan, ConsoleColor.Black, caption + "\n" + message + " ");               
            }
            var results = new Dictionary<string, PSObject>();
            foreach (FieldDescription fd in descriptions)
            {
                string[] label = GetHotkeyAndLabel(fd.Label);
                this.WriteLine(label[1]);
                string userData = Console.ReadLine();
                if (userData == null)
                {
                    return null;
                }


                results[fd.Name] = PSObject.AsPSObject(userData);
            }


            return results;
        }


        public override PSCredential PromptForCredential(string caption, string message, string userName, string targetName)
        {
            throw new NotImplementedException();
        }


        public override PSCredential PromptForCredential(string caption, string message, string userName, string targetName, PSCredentialTypes allowedCredentialTypes, PSCredentialUIOptions options)
        {
            throw new NotImplementedException();
        }


        public override int PromptForChoice(string caption, string message, Collection<ChoiceDescription> choices, int defaultChoice)
        {
            // Write the caption and message strings in Blue.
            this.WriteLine(ConsoleColor.Blue, ConsoleColor.Black, caption + "\n" + message + "\n");


            // Convert the choice collection into something that is
            // easier to work with. See the BuildHotkeysAndPlainLabels
            // method for details.
            string[,] promptData = BuildHotkeysAndPlainLabels(choices);


            // Format the overall choice prompt string to display.
            var sb = new StringBuilder();
            for (int element = 0; element < choices.Count; element++)
            {
                sb.Append(String.Format(CultureInfo.CurrentCulture, "|{0}> {1} ", promptData[0, element], promptData[1, element]));
            }


            sb.Append(String.Format(CultureInfo.CurrentCulture, "[Default is ({0}]", promptData[0, defaultChoice]));


            // Read prompts until a match is made, the default is
            // chosen, or the loop is interrupted with ctrl-C.
            while (true)
            {
                this.WriteLine(sb.ToString());
                string data = Console.ReadLine().Trim().ToUpper(CultureInfo.CurrentCulture);


                // If the choice string was empty, use the default selection.
                if (data.Length == 0)
                {
                    return defaultChoice;
                }


                // See if the selection matched and return the
                // corresponding index if it did.
                for (int i = 0; i < choices.Count; i++)
                {
                    if (promptData[0, i] == data)
                    {
                        return i;
                    }
                }


                this.WriteErrorLine("Invalid choice: " + data);
            }
        }


        #region IHostUISupportsMultipleChoiceSelection Members


        public Collection<int> PromptForChoice(string caption, string message, Collection<ChoiceDescription> choices, IEnumerable<int> defaultChoices)
        {
            this.WriteLine(ConsoleColor.Blue, ConsoleColor.Black, caption + "\n" + message + "\n");


            string[,] promptData = BuildHotkeysAndPlainLabels(choices);


            var sb = new StringBuilder();
            for (int element = 0; element < choices.Count; element++)
            {
                sb.Append(String.Format(CultureInfo.CurrentCulture, "|{0}> {1} ", promptData[0, element], promptData[1, element]));
            }


            var defaultResults = new Collection<int>();
            if (defaultChoices != null)
            {
                int countDefaults = 0;
                foreach (int defaultChoice in defaultChoices)
                {
                    ++countDefaults;
                    defaultResults.Add(defaultChoice);
                }


                if (countDefaults != 0)
                {
                    sb.Append(countDefaults == 1 ? "[Default choice is " : "[Default choices are ");
                    foreach (int defaultChoice in defaultChoices)
                    {
                        sb.AppendFormat(CultureInfo.CurrentCulture, "\"{0}\",", promptData[0, defaultChoice]);
                    }
                    sb.Remove(sb.Length - 1, 1);
                    sb.Append("]");
                }
            }


            this.WriteLine(ConsoleColor.Cyan, ConsoleColor.Black, sb.ToString());


            var results = new Collection<int>();
            while (true)
            {
            ReadNext:
                string prompt = string.Format(CultureInfo.CurrentCulture, "Choice[{0}]:", results.Count);
                this.Write(ConsoleColor.Cyan, ConsoleColor.Black, prompt);
                string data = Console.ReadLine().Trim().ToUpper(CultureInfo.CurrentCulture);


                if (data.Length == 0)
                {
                    return (results.Count == 0) ? defaultResults : results;
                }


                for (int i = 0; i < choices.Count; i++)
                {
                    if (promptData[0, i] == data)
                    {
                        results.Add(i);
                        goto ReadNext;
                    }
                }


                this.WriteErrorLine("Invalid choice: " + data);
            }
        }


        #endregion


        private static string[,] BuildHotkeysAndPlainLabels(Collection<ChoiceDescription> choices)
        {
            // Allocate the result array
            string[,] hotkeysAndPlainLabels = new string[2, choices.Count];


            for (int i = 0; i < choices.Count; ++i)
            {
                string[] hotkeyAndLabel = GetHotkeyAndLabel(choices[i].Label);
                hotkeysAndPlainLabels[0, i] = hotkeyAndLabel[0];
                hotkeysAndPlainLabels[1, i] = hotkeyAndLabel[1];
            }


            return hotkeysAndPlainLabels;
        }


        private static string[] GetHotkeyAndLabel(string input)
        {
            string[] result = new string[] { String.Empty, String.Empty };
            string[] fragments = input.Split('&');
            if (fragments.Length == 2)
            {
                if (fragments[1].Length > 0)
                {
                    result[0] = fragments[1][0].ToString().
                    ToUpper(CultureInfo.CurrentCulture);
                }


                result[1] = (fragments[0] + fragments[1]).Trim();
            }
            else
            {
                result[1] = input;
            }


            return result;
        }
    }


    class HostRawUserInterface : PSHostRawUserInterface
    {
        public override KeyInfo ReadKey(ReadKeyOptions options)
        {
            throw new NotImplementedException();
        }


        public override void FlushInputBuffer()
        {
        }


        public override void SetBufferContents(Coordinates origin, BufferCell[,] contents)
        {
            throw new NotImplementedException();
        }


        public override void SetBufferContents(Rectangle rectangle, BufferCell fill)
        {
            throw new NotImplementedException();
        }


        public override BufferCell[,] GetBufferContents(Rectangle rectangle)
        {
            throw new NotImplementedException();
        }


        public override void ScrollBufferContents(Rectangle source, Coordinates destination, Rectangle clip, BufferCell fill)
        {
            throw new NotImplementedException();
        }


        public override ConsoleColor ForegroundColor
        {
            get { return Console.ForegroundColor; }
            set { Console.ForegroundColor = value; }
        }


        public override ConsoleColor BackgroundColor
        {
            get { return Console.BackgroundColor; }
            set { Console.BackgroundColor = value; }
        }


        public override Coordinates CursorPosition
        {
            get { return new Coordinates(Console.CursorLeft, Console.CursorTop); }
            set { Console.SetCursorPosition(value.X, value.Y); }
        }


        public override Coordinates WindowPosition
        {
            get { return new Coordinates(Console.WindowLeft, Console.WindowTop); }
            set { Console.SetWindowPosition(value.X, value.Y); }
        }


        public override int CursorSize
        {
            get { return Console.CursorSize; }
            set { Console.CursorSize = value; }
        }


        public override Size BufferSize
        {
            get { return new Size(Console.BufferWidth, Console.BufferHeight); }
            set { Console.SetBufferSize(value.Width, value.Height); }
        }


        public override Size WindowSize
        {
            get { return new Size(Console.WindowWidth, Console.WindowHeight); }
            set { Console.SetWindowSize(value.Width, value.Height); }
        }


        public override Size MaxWindowSize
        {
            get { return new Size(Console.LargestWindowWidth, Console.LargestWindowHeight); }
        }


        public override Size MaxPhysicalWindowSize
        {
            get { return new Size(Console.LargestWindowWidth, Console.LargestWindowHeight); }
        }


        public override bool KeyAvailable
        {
            get { return Console.KeyAvailable; }
        }


        public override string WindowTitle
        {
            get { return Console.Title; }
            set { Console.Title = value; }
        }
    }
}
'@
}   


Process {
    if ($psCmdlet.ParameterSetName -eq "Path")
    {
        # In the -Path (non-literal) case we may need to resolve a wildcarded path
        $resolvedPaths = @($Path | Resolve-Path | Convert-Path)
    }
    else
    {
        # Must be -LiteralPath
        $resolvedPaths = @($LiteralPath | Convert-Path)
    }
 
    foreach ($rpath in $resolvedPaths)
    {
        Write-Verbose "Processing $rpath"


        $gzItem = Get-ChildItem $rpath | Write-GZip -Quiet
        $resourcePath = "$($gzItem.Directory)\Resources.Script.ps1.gz"
        if (Test-Path $resourcePath) { Remove-Item $resourcePath }
        Rename-Item $gzItem $resourcePath
       
        # Configure the compiler parameters
        $referenceAssemblies = 'System.dll',([psobject].Assembly.Location)
        $outputPath = $OutputAssembly
        if (![IO.Path]::IsPathRooted($outputPath))
        {
            $outputPath = [io.path]::GetFullPath((Join-Path $pwd $outputPath))
        }
        if ($rpath -eq $outputPath)
        {
            throw 'Oops, you don''t really want to overwrite your script with an EXE.'
        }


        $cp = new-object System.CodeDom.Compiler.CompilerParameters $referenceAssemblies,$outputPath,$true
        $cp.TempFiles = new-object System.CodeDom.Compiler.TempFileCollection ([IO.Path]::GetTempPath())
        $cp.GenerateExecutable = $true
        $cp.GenerateInMemory   = $false
        $cp.IncludeDebugInformation = $true
        if ($IconPath)
        {
            $rIconPath = Resolve-Path $IconPath
            $cp.CompilerOptions = " /win32icon:$rIconPath"
        }
        [void]$cp.EmbeddedResources.Add($resourcePath)
       
        # Create the C# codedom compiler
        $dict = new-object 'System.Collections.Generic.Dictionary[string,string]'
        $dict.Add('CompilerVersion','v3.5')
        $provider = new-object Microsoft.CSharp.CSharpCodeProvider $dict
       
        # Compile the source and report errors
        $results = $provider.CompileAssemblyFromSource($cp, $src)
        if ($results.Errors.Count)
        {
            $errorLines = ""
            foreach ($error in $results.Errors)
            {
                $errorLines += "`n`t" + $error.Line + ":`t" + $error.ErrorText
            }
            Write-Error $errorLines
        }
    } 
}

Sunday, September 19, 2010  |  From Keith Hill's Blog

We had some boiler plate code that we always put into our scripts to set strict mode and to compute $ScriptDir so the script can load other scripts relatively to its location.  This boiler plate code is simple:

#requires –Version 2.0
Set-StrictMode –Version 2.0
$ScriptDir = Split-Path $MyInvocation.MyCommand.Path –Parent

However lets say you do this in all your scripts and one script (Parent.ps1) dot-sources another script (PoshLib.ps1) that does the same trick e.g.:

Parent.ps1:
$ScriptDir = Split-Path $MyInvocation.MyCommand.Path –Parent
"PARENT:  Before dot-sourcing libary ScriptDir is $ScriptDir"
. $ScriptDir\Bin\PoshLib.ps1
"PARENT:  After dot-sourcing libary ScriptDir is $ScriptDir"

PoshLib.ps1
$ScriptDir = Split-Path $MyInvocation.MyCommand.Path –Parent
"POSHLIB: ScriptDir is $ScriptDir"

Seems innocent enough but check out the output of running Parent.ps1:

PS C:\Users\Keith> C:\Users\Keith\Parent.ps1
PARENT:  Before dot-sourcing libary ScriptDir is C:\Users\Keith
POSHLIB: ScriptDir is C:\Users\Keith\Bin
PARENT:  After dot-sourcing libary ScriptDir is C:\Users\Keith\Bin

What happens here is that because we are “dot sourcing” PoshLib.ps1 into Parent.ps1, its definition of the $ScriptDir variable stomps the one created in Parent.ps1.  Obviously this won’t do.  You could try to create unique variable names for each script but that isn’t ideal and not very maintainable. 

The best answer if you are on PowerShell 2.0 is to just use modules for your libraries.  Modules can have “private” variables that don’t get exported so the variable “stomping” issue never arises.  However, for various reasons, folks can’t always upgrade to PowerShell 2.0.  So here is how you can fix this issue on PowerShell 1.0. 

Essentially what you want to do is to dynamically evaluate the script’s location every time without having to use the longhand:

Split-Path $MyInvocation.MyCommand.Path –Parent

PowerShell allows us to create a shorthand for this using an anonymous scriptblock assigned to a variable like so:

Parent.ps1:
$ScriptDir = { Split-Path $MyInvocation.ScriptName –Parent }
"PARENT:  Before dot-sourcing libary ScriptDir is $(&$ScriptDir)"
. "$(&$ScriptDir)\Bin\PoshLib.ps1"
"PARENT:  After dot-sourcing libary ScriptDir is $(&$ScriptDir)"

PoshLib.ps1
$ScriptDir = { Split-Path $MyInvocation.ScriptName –Parent }
"POSHLIB: ScriptDir is $(&$ScriptDir)"

Note: that once we put the code within the scriptblock we need to switch from $MyInvocation.MyCommand.Path to $MyInvocation.ScriptName.  These changes yield the desired results:

PS C:\Users\Keith> C:\Users\Keith\Parent.ps1
PARENT:  Before dot-sourcing libary ScriptDir is C:\Users\Keith
POSHLIB: ScriptDir is C:\Users\Keith\Bin
PARENT:  After dot-sourcing libary ScriptDir is C:\Users\Keith

Sunday, September 19, 2010  |  From Keith Hill's Blog

We all tend to customize our PowerShell environment via our Profile.ps1 script.  Whether we load up snapins, modules, our own functions, etc.  And with PowerShell 2.0, you can even “proxy” cmdlets such that you get to intercept calls to cmdlets like Get-Help and add parameters and augment its functionality. Sometimes though this can cause problems.  And it isn’t always easy to determine if the problem is with PowerShell or one of these add-ins.  When I run into these situations I fire up a PowerShell with no profile to help determine where the problem actually lies.  This is what I execute:

C:\PS> PowerShell –noprofile

Often I prefer to have PowerShell fire up in a different window so I use Start-Process.  And because I do this so often (testing PSCX), I’ve created a function that I put in my profile to provide a convenient shortcut to fire up PowerShell with no profile:

function psnp { Start-Process PowerShell.exe -Arg -noprofile }

Tuesday, July 06, 2010  |  From Keith Hill's Blog

The TFPT PowerShell snapin is a nice start but it is missing a key cmdlet IMO and that is Get-TfsPermission.  Since TFS allows you to add individual users all over your directory structure, it can be quite hard rationalizing exactly who has access to what without traversing a bunch of directories in the Team Foundation client’s Source Control window, opening the Properties dialog and inspecting the Security settings.  Fortunately there is also a command line way to do this via TFS’s tf.exe utility.  Unfortunately the output of this command is just text and what’s worse is that this text is a pain to query over using PowerShell’s built-in querying cmdlets.  So I wrote the following function to convert this text into objects which enables easier querying:

<#
.SYNOPSIS
    Gets the Team Foundation server permissions for items based on the specified paths.
.DESCRIPTION
    Gets the Team Foundation server permissions for items based on the specified paths and outputs rich
    objects as opposed to text.
.PARAMETER Path
    The path to the Team Foundation server item.
.PARAMETER LiteralPath
    Specifies a path to one or more locations. Unlike Path, the value of LiteralPath is used exactly as it
    is typed. No characters are interpreted as wildcards. If the path includes escape characters, enclose
    it in single quotation marks. Single quotation marks tell Windows PowerShell not to interpret any
    characters as escape sequences.
.PARAMETER Recurse
    Gets permissions for the items at the specified location and in all child locations.
.EXAMPLE
    C:\PS> Get-TfsPermission C:\Tfs\Acme\Branches\Release\3.7 | Select ServerItem -exp Identities
    Get the permissions for the specified folder and expands the Identities array to show each identity.
    The server item corresponding to each identity object is tagged onto the object.
.EXAMPLE
    C:\PS> Get-TfsPermission C:\Tfs\Acme | Select ServerItem -expand Identities | Where {$_.Allow -match 'Checkin' } | Format-List ServerItem,Identity,Allow,Deny   
    This command looks for items where the 'checkin' privilege has been granted locally.
.NOTES
    Author: Keith Hill
    Date:   June 28, 2010   
#>
function Get-TfsPermission
{
    [CmdletBinding(DefaultParameterSetName="Path")]
    param(
        [Parameter(Mandatory=$true, Position=0, ParameterSetName="Path",
                   ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true,
                   HelpMessage="Path to workspace item")]
        [ValidateNotNullOrEmpty()]
        [string[]]
        $Path,
       
        [Alias("PSPath")]
        [Parameter(Mandatory=$true, Position=0, ParameterSetName="LiteralPath",
                   ValueFromPipelineByPropertyName=$true,
                   HelpMessage="Path to workspace item")]
        [ValidateNotNullOrEmpty()]
        [string[]]
        $LiteralPath,
       
        [Parameter()]
        [switch]
        $Recurse
    )

    Begin
    {
        Set-StrictMode -Version Latest
        $item = $null
    }

    Process
    {
        if ($psCmdlet.ParameterSetName -eq "Path")
        {
            # In the -Path (non-literal) case we may need to resolve a wildcarded path
            $resolvedPaths = @($Path | Resolve-Path | Convert-Path)
        }
        else
        {
            # Must be -LiteralPath
            $resolvedPaths = @($LiteralPath | Convert-Path)
        }
    
        foreach ($rpath in $resolvedPaths)
        {
            Write-Verbose "Processing $rpath"
           
            $tfargs = ''
            $tfargs += if ($Recurse) { '/r' }
           
            # Look at each line of TF PERMISSION output and use a regex to determine
            # what the data for the line is.
            switch -regex (tf permission $rpath $tfargs)
            {
                '^Server item:\s+(\S+)\s+\(Inherit:\s+(\w+)\)'
                {
                    # If previous object exists, output it before creating a new one
                    if ($item) { $item }
                    $item = new-object psobject  -property @{
                        ServerItem = $matches[1]
                        Inherits   = $matches[2] -eq 'yes'
                        Identities = @()
                    }
                    $item.psobject.TypeNames[0] = "TfsTools.VersionControl.ItemPermissions"  
                }
               
                '\bIdentity:\s+(.*)$'  
                {
                    $identityName = $matches[1]
                    $currentIdentity = new-object psobject -property @{
                        Identity = $identityName
                        Allow = ''
                        Deny = ''
                        InheritedAllow = ''
                        InheritedDeny = ''
                    }
                    $item.Identities += $currentIdentity
                }
               
                '\bAllow:\s*(.*)$'     
                {
                    $currentIdentity.Allow = $matches[1]
                }
               
                '\bDeny:\s*(.*)$'      
                {
                    $currentIdentity.Deny = $matches[1]
                }
               
                '\bAllow\s+\(Inherited\)\s*:\s*(.*)$'     
                {
                    $currentIdentity.InheritedAllow = $matches[1]
                }
               
                '\bDeny\s+\(Inherited\)\s*:\s*(.*)$'      
                {
                    $currentIdentity.InheritedDeny = $matches[1]
                }           
            }
        }
    }

    End
    {
        # Output the very last object
        if ($item) { $item }
    }
}

The output of this function isn’t great for viewing since it is primarily intended to enable querying of the permission info on each server item.  Note to the Team Foundation Power Tools devs, it sure would be nice to get this functionality into a future TFPT drop.

Thursday, May 27, 2010  |  From Keith Hill's Blog

If you are dealing with an native executable that outputs UTF8 with no BOM (byte order marker) you will find that PowerShell garbles the input.  This is most likely an issue with how the .NET console code interprets the incoming byte stream.  Without a BOM it isn’t exactly easy to determine the proper encoding for a stream of bytes.  For example take the following simple native exe source code that is supposed to output this (BTW ignore the fact that the text says ‘ASCII’ – it is really UTF8):

ASCII outputᾹ

Contents of stdout.cpp:

#include <stdio.h> 
 
void main() 
{ 
    char bytes[] = { 0x41, 0x53, 0x43, 0x49,  
                     0x49, 0x20, 0x6F, 0x75,  
                     0x74, 0x70, 0x75, 0x74, 
                     0xE1, 0xBE, 0xB9}; 
 
    for (int i = 0; i < 15; i++) 
    { 
        printf("%c", bytes[i]); 
    }                 
} 

If you pipe the output of this program into a PSCX utility called Format-Hex (alias is fhex), you can see the actual unicode byte stream that was created by .NET’s interpretation of the incoming byte stream.





PS> .\stdout.exe | fhex

Address:  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F ASCII
-------- ----------------------------------------------- ----------------
00000000 41 00 53 00 43 00 49 00 49 00 20 00 6F 00 75 00 A.S.C.I.I. .o.u.
00000010 74 00 70 00 75 00 74 00 DF 00 5B 25 63 25       t.p.u.t...[%c%


You might think you could pipe the output to Out-File –Encoding Utf8 but by the time the .NET strings hit the Out-File cmdlet the damage is already done.  As can be seen if you view the subsequent output in Notepad.exe:


ASCII outputᾹ


The solution to this problem is to provide a hint to the .NET console functionality about the encoding of the incoming bytes.  You can do this very simply:





PS> [System.Console]::OutputEncoding = [System.Text.Encoding]::UTF8


And it works:





6> .\stdout.exe | fhex

Address:  0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F ASCII
-------- ----------------------------------------------- ----------------
00000000 41 00 53 00 43 00 49 00 49 00 20 00 6F 00 75 00 A.S.C.I.I. .o.u.
00000010 74 00 70 00 75 00 74 00 B9 1F                   t.p.u.t...

7> .\stdout.exe | Out-File good.txt -Encoding UTF8


If you open good.txt in notepad you get:


ASCII outputᾹ


And is as it should be.  However this may seem somewhat counter-intuitive (it did to me) since the problem is with PowerShell/.NET “reading” console input and not writing it.  Well one of the good folks on the PowerShell team pointed out to me that the Console OutputEncoding is probably inherited by child processes and a quick little experiment reveals this to be true.  So by setting the OutputEncoding this determines how .NET encodes console output which helps PowerShell/.NET determine the correct encoding when reading in this information via console input.


One last point on this approach is that you should stash the original value of [Console]::OutputEncoding and restore it after you’ve run a problematic exe like in this example.  I’ve found that the C# compiler will crash if you run it in PowerShell with the [Console]::OutputEncoding set to UTF8.

Tuesday, May 11, 2010  |  From Keith Hill's Blog

Some questions are coming up about the contents of PSCX 2.0.  Here’s what in it:

CMDLETS:

Add-PathVariable
Clear-MSMQueue
ConvertFrom-Base64
ConvertTo-Base64
ConvertTo-MacOs9LineEnding
ConvertTo-Metric
ConvertTo-UnixLineEnding
ConvertTo-WindowsLineEnding
Convert-Xml
Disconnect-TerminalSession
Expand-Archive
Export-Bitmap
Format-Byte
Format-Hex
Format-Xml
Get-ADObject
Get-AdoConnection
Get-AdoDataProvider
Get-AlternateDataStream
Get-Clipboard
Get-DhcpServer
Get-DomainController
Get-DriveInfo
Get-EnvironmentBlock
Get-FileTail
Get-FileVersionInfo
Get-ForegroundWindow
Get-Hash
Get-HttpResource
Get-LoremIpsum
Get-MountPoint
Get-MSMQueue
Get-OpticalDriveInfo
Get-PathVariable
Get-PEHeader
Get-Privilege
Get-PSSnapinHelp
Get-ReparsePoint
Get-ShortPath
Get-TabExpansion
Get-TerminalSession
Get-TypeName
Get-Uptime
Import-Bitmap
Invoke-AdoCommand
Invoke-Apartment
Join-String
New-Hardlink
New-Junction
New-MSMQueue
New-Shortcut
New-Symlink
Out-Clipboard
Ping-Host
Pop-EnvironmentBlock
Push-EnvironmentBlock
Read-Archive
Receive-MSMQueue
Remove-AlternateDataStream
Remove-MountPoint
Remove-ReparsePoint
Resolve-Host
Send-MSMQueue
Send-SmtpMail
Set-BitmapSize
Set-Clipboard
Set-FileTime
Set-ForegroundWindow
Set-PathVariable
Set-Privilege
Set-VolumeLabel
Skip-Object
Split-String
Start-TabExpansion
Stop-TerminalSession
Test-AlternateDataStream
Test-Assembly
Test-MSMQueue
Test-Script
Test-UserGroupMembership
Test-Xml
Unblock-File
Write-BZip2
Write-Clipboard
Write-GZip
Write-Tar
Write-Zip

FUNCTIONS:

Add-DirectoryLength
Add-ShortPath
Dismount-VHD
Edit-File
Edit-HostProfile
Edit-Profile
Enable-OpenPowerShellHere
Get-ChildItem
Get-Help
Get-PropertyValue
Get-ScreenCss
Get-ScreenHtml
Get-ViewDefinition
help
Invoke-BatchFile
Invoke-Elevated
Invoke-GC
Invoke-Method
Invoke-NullCoalescing
Invoke-Reflector
Invoke-Ternary
less
Mount-VHD
New-HashObject
Out-Speech
prompt
QuoteList
QuoteString
Resolve-ErrorRecord
Resolve-HResult
Resolve-WindowsError
Search-Transcript
Set-LocationEx
Set-ReadOnly
Set-Writable
Show-Tree
Stop-RemoteProcess

ALIASES:

?:
??
call
cvxml
e
ehp
ep
fhex
fxml
gcb
gpv
gtn
igc
ln
lorem
nho
ocb
ql
qs
Resize-Bitmap
rf
rver
rvhr
rvwer
skip
sls
sro
srts
su
swr
tail
touch

PROVIDERS:

AssemblyCache
DirectoryServices
PscxSettings
FeedStore

Tuesday, May 11, 2010  |  From Keith Hill's Blog

One issue with PowerShell providers is that only the Filesystem and Registry providers’ hierarchies are easily viewable using Windows Explorer and Regedit respectively.  The other PowerShell providers are mostly without such a view.  This is problematic for providers that supply configuration information like the WSMan provider.  Without a lot of cd’ing around it is hard to get a “lay of the land” with respect to the various settings that are available. 

In Pscx 2.0, we set out to help with this problem by providing the equivalent of the old DOS tree.com routine.  The command is called Show-Tree.  If you have the final PSCX 2.0 bits installed try this from an elevated prompt:

C:\PS> Show-Tree wsman: -ShowLeaf
WSMan:\
└──localhost
   ├──MaxEnvelopeSizekb
   ├──MaxTimeoutms
   ├──MaxBatchItems
   ├──MaxProviderRequests
   ├──Client
   │  ├──NetworkDelayms
   │  ├──URLPrefix
   │  ├──AllowUnencrypted
   │  ├──Auth
   │  │  ├──Basic
   │  │  ├──Digest
   │  │  ├──Kerberos
   │  │  ├──Negotiate
   │  │  ├──Certificate
   │  │  └──CredSSP
   │  ├──DefaultPorts
   │  │  ├──HTTP
   │  │  └──HTTPS
   │  └──TrustedHosts
   ├──Service
   │  ├──RootSDDL
   │  ├──MaxConcurrentOperations
   │  ├──MaxConcurrentOperationsPerUser
   │  ├──EnumerationTimeoutms
   │  ├──MaxConnections
   │  ├──MaxPacketRetrievalTimeSeconds
   │  ├──AllowUnencrypted
   │  ├──Auth
   │  │  ├──Basic
   │  │  ├──Kerberos
   │  │  ├──Negotiate
   │  │  ├──Certificate
   │  │  ├──CredSSP
   │  │  └──CbtHardeningLevel
   │  ├──DefaultPorts
   │  │  ├──HTTP
   │  │  └──HTTPS
   │  ├──IPv4Filter
   │  ├──IPv6Filter
   │  ├──EnableCompatibilityHttpListener
   │  ├──EnableCompatibilityHttpsListener
   │  └──CertificateThumbprint
   ├──Shell
   │  ├──AllowRemoteShellAccess
   │  ├──IdleTimeout
   │  ├──MaxConcurrentUsers
   │  ├──MaxShellRunTime
   │  ├──MaxProcessesPerShell
   │  ├──MaxMemoryPerShellMB
   │  └──MaxShellsPerUser
   ├──Listener
   │  └──Listener_641507880
   │     ├──Address
   │     ├──Transport
   │     ├──Port
   │     ├──Hostname
   │     ├──Enabled
   │     ├──URLPrefix
   │     ├──CertificateThumbprint
   │     ├──ListeningOn_1770022257
   │     ├──ListeningOn_1480808289
   │     ├──ListeningOn_4173834
   │     ├──ListeningOn_228071226
   │     ├──ListeningOn_1414502903
   │     ├──ListeningOn_222657401
   │     ├──ListeningOn_616175923
   │     ├──ListeningOn_783876958
   │     ├──ListeningOn_704030885
   │     ├──ListeningOn_405255605
   │     └──ListeningOn_1490189075
   ├──Plugin
   │  ├──Event Forwarding Plugin
   │  │  ├──xmlns
   │  │  ├──Name
   │  │  ├──Filename
   │  │  ├──SDKVersion
   │  │  ├──XmlRenderingType
   │  │  ├──lang
   │  │  ├──InitializationParameters
   │  │  └──Resources
   │  │     └──Resource_1958972577
   │  │        ├──ResourceUri
   │  │        ├──SupportsOptions
   │  │        ├──ExactMatch
   │  │        ├──Capability
   │  │        └──Security
   │  │           └──Security_371857150
   │  │              ├──Uri
   │  │              ├──ExactMatch
   │  │              ├──Sddl
   │  │              └──xmlns
   ...

You can use this on most providers although some providers behave better than others under this command.  Here’s a way to view registry entries e.g.:

C:\PS> Show-Tree HKLM:\SOFTWARE\Microsoft\.NETFramework -Depth 2 -ShowProperty
HKLM:\SOFTWARE\Microsoft\.NETFramework
├──Property: COMPLUS_HACK_DisableSideBySide = 1
├──Property: DbgJITDebugLaunchSetting = 16
├──Property: DbgManagedDebugger = "C:\Windows\system32\vsjitdebugger.exe" PID %d APPDOM %d EXTEXT "%s" EVTHDL %d
├──Property: Enable64Bit = 1
├──Property: InstallRoot = C:\Windows\Microsoft.NET\Framework64\
├──AssemblyFolders
│  ├──Property: SubKeyCount = 10
│  ├──Property: ValueCount = 0
│  ├──ADOMD.Client 10.0
│  │  └──Property: (default) = C:\Program Files\Microsoft.NET\ADOMD.NET\100\
│  ├──Microsoft .NET Framework 3.5 Reference Assemblies
│  │  └──Property: (default) = C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\
│  ├──MSDeploy
│  │  └──Property: (default) = C:\Program Files\IIS\Microsoft Web Deploy\
│  ├──SQL Server Assemblies
│  │  └──Property: (default) = C:\Program Files\Microsoft SQL Server\100\SDK\Assemblies\
│  ├──SSIS Connection Managers 100
│  │  └──Property: (default) =
│  ├──SSIS ForEach Enumerators 100
│  │  └──Property: (default) = C:\Program Files\Microsoft SQL Server\100\DTS\ForEachEnumerators
│  ├──SSIS Pipeline Components 100
│  │  └──Property: (default) = C:\Program Files\Microsoft SQL Server\100\DTS\PipelineComponents\
│  ├──SSIS Tasks 100
│  │  └──Property: (default) = C:\Program Files\Microsoft SQL Server\100\DTS\Tasks
│  ├──v3.0
│  │  ├──Property: <IncludeDotNet2Assemblies> = 1
│  │  └──Property: All Assemblies In = C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\
│  └──v3.5
│     ├──Property: <IncludeDotNet2Assemblies> = 1
│     └──Property: All Assemblies In = C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\
├──NGenQueue
│  ├──Property: SubKeyCount = 2
│  ├──Property: ValueCount = 0
│  ├──WIN32
│  │  ├──Property: SubKeyCount = 2
│  │  └──Property: ValueCount = 0
│  └──WIN64
│     ├──Property: SubKeyCount = 2
│     └──Property: ValueCount = 0
...

Give PSCX 2.0 a try and let us know what you think - good or bad!

Tuesday, May 11, 2010  |  From Keith Hill's Blog

Finally! We’ve gotten PSCX 2.0 finished and released.  A few notes about this release.  It targets only Windows PowerShell 2.0 as it is module based.  Also, the deployment of the PSCX 2.0 is xcopy.  There is no installer.  For more more info, check out the releases notes on the PSCX 2.0 download page.  Please let us know if you find any issues.  NOTE: Be sure to Unblock the ZIP before extracting it to your Modules folder.

 Keith Hill's Blog News Feed 

 Technorati Search for: PowerShell AND (Cmdlet OR Provider) News Feed 

One of the big benefits of Windows 2008 R2 is the fact that PowerShell v2 is installed by default and that AD can be administered by PowerShell. There are 76 AD cmdlets and an AD provider. We’ll start by looking at the cmdlets. Organizational Units are the subdivisions with a domain. We can easily create a new OU. New-ADOrganizationalUnit -Name "AllUsers" -ProtectedFromAccidentalDeletion $true The default location is to create OUs in the root of the domain. I really like the ability to...( read

From what I can see, CTP3's scoped execution policy settings can be used to cause a change in PowerShell behavior that can't be reversed intuitively. See this suggestion on Microsoft Connect: Possible need for Clear-ExecutionPolicy https://connect.microsoft.com/feedba...9788&SiteID=99 Basically, PowerShell sessions inherit machine-scoped execution policies until you define an execution policy with user scope. Once you've created a user-scoped execution policy, you can modify it, but

Updated to PowerBoots 0.1 An introduction to PowerBoots Please excuse me if I start by just copying the basic ideas of the Shoes Tutorial , but I figured that since PowerBoots is inspired by Shoes, that was as good a place as any to start. PowerBoots (or just “Boots”) is a PowerShell 2.0 module with functions for writing Windows Presentation Framework ( WPF ) applications in the PowerShell scripting language. You should get the latest version of PowerBoots before continuing, and ins

Andrew Kutz just posted a new Hyper9 Cmdlet on sourceforce.net called Out-DataSet. Out-DataSet is an extremely useful and needed cmdlet. You can use it to pipe any type of data that can be formatted with the built-in cmdlet, Format-Table, into a typed Microsoft .NET System.Data.DataSet. This allows an unlimited manipulation of data that you simply cannot achieve with text globbing. This cmdlet is experimental in nature because it was achieved by reverse engineering the Format-Table cmdlet

• Updates : 3/28/2009 and 3/29/2009 Note: This post is updated daily or more frequently, depending on the availability of new articles. Entity Framework and Entity Data Model (EF/EDM) • Julie Lerman takes on many-to-many associations again in her Inserting Many to Many Relationships in EF with or without a Join Entity post of 3/29/2009. Binary Bob ’s Disconnected Clients, Changed data and Entity Framework post of 3/25/2009 discusses the use of EF with Silverlight apps. B

Ya hemos comentado en articulos anteriores sobre Windows Powershell lo que son los commandlets. Hoy vamos a ver uno de ellos que nos facilitara en un momento dado el trabajo. 4.1- Get-command Este cmdlet obtiene informacion basica acerca de los cmdlets y otros elementos de comandos de Windows Powershell como archivos, funciones y proveedores de Windows Powershell. Parametros: -name Obtiene...

While I finish up another blog solution, this time on importing a table from Word into Excel, I thought I would share some information on two useful tools you guys can leverage when building Open XML solutions. The first tool I want to talk about is the next release of PowerTools for Open XML. PowerTools for Open XML is an open source project on CodePlex , which is entirely based on version 1 of the Open XML SDK. This tool supports the PowerShell piping architecture, by providing 30+ cmdlets.

This is a bit of a hardcore example of the power that modules have brought to the table in v2.0. First, a little background - PowerShell’s type adaptation system has always ignored the concept of interfaces. Frankly, it never really needed to pay them any attention. The adapted view of any instance of a .NET class is just an aggregate of all its methods; the most derived instance is the default, and only, view. This is the most simple and most frequently used view. However, this all goes to hell

————————————————————————————————————— ————————————————————————————————————— Veeam Software , award-winning provider of systems management tools for VMware virtual datacenter environments, today delivers new executive management reporting, integration with corporate CMDBs (change management databases), new change management capabilities, and numerous technical enhancements in version 3.5 of its Veeam Reporter and Veeam Reporter Enterprise products. Veeam Reporter is a favorite of virtual

If you’re getting your Powershell on ( and frankly you should ), Microsoft have released a ~440 page compendium ( in *.docx format )   of Cmdlets you can use under the SCVMM Powershell. Now just remember the easiest way to get thru the document is view the Document Map . ( click View and then select the Document Map check box ) The reference is a prettied up and portable version of:  Get-Command -PSSnapin Microsoft.SystemCenter.VirtualMachineManager | Sort?Object Noun, Verb | Get-H

  Silverlight / WPF Boss Launch Beta (Andy Beaulieu) Silverlight RPG: Steel Saga (Avi Pilosof) Silverlight 3 Beta - Downloads You May Have Missed (Bart Czernicki) Compile your XNA 2D games to run in Silverlight with SilverSprite (Bill Reiss) Silverlight, XAML & Prism: Diving in Head First at the Shallow End of the Pool (Bobby Johnson) Creating Sound Using MediaStreamSource in Silverlight 3 Beta   and   Using Blur to make Dialogs Pop in Silverlight 3 (Pete Brown)

A Podcast about Windows PowerShell. Listen: In This Episode Tonight on the PowerScripting Podcast we talk to Brandon Shell about Active Directory support in PowerShell V2 News This segment is brought to you by Idera: Want to make Windows PowerShell easier than ever to learn and master? Checkout Idera’s PowerShellPlus Professional Edition which is now available for download! The new version has vastly improved code completion and a slick interactive Learning Cen

Windows Azure, Azure Data Services, SQL Data Services and related cloud computing topics now appear in this weekly series. Note: This post is updated daily or more frequently, depending on the availability of new articles. • • • Updated 3/20/2009 and 3/21/2009: Additions •• Updated 3/19/2009 10:00 AM PDT: Addition of more MIX 09-based content • Updated 3/18/2009 11:00 AM PDT: Additions: Windows Azure Tools and SDK March CTP update, ADO.NET Data Services 1.5 March CTP

There’s a bit of a flap going on now around the blogosphere as various vendors, eager to get onto the PowerShell train, are doing the bare minimum to get their product “powershellized.” No one has spent any time reading – or if they did, they weren’t successful in trying to understand it – the Microsoft Command Line Standard . Modules as Namespaces That’s right, modules are not as crazy sounding as they seem. They can be used quite simply to just group a load of function

GoGrid continues to be a pioneering force in Cloud Computing Infrastructure and Hosting segments with a variety of initiatives, making it a clear choice for Windows Server 2008, 2003, SQL Server and .NET developers. San Francisco, CA ( Vocus / PRWEB ) March 17, 2009 — GoGrid , the Cloud Computing division of ServePath , LLC delivers a solid implementation of programs, services and features optimized for Mi

After being a part of a few email threads and discussions about Citrix not following the traditional name-verb cmdlet naming scheme I thought I would make a post with my take on that. Basically, Citrix joined companies like Microsoft, VMware and Quest and is also trying to PowerShell-enable all of their products. However, they chose to not follow the standard naming scheme and went with a few of their own. The ones for Provisioning Server are just bad: They user verb instead of a noun, p

Windows PowerShell で SQL Server 2008 を管理する方法を調べてみました。 今回使用した SQL Server は SQL Server 2008 Express になります。 最初、SQL Server 2008 Express では Windows PowerShell が使用できないかと思っていたのですが、Windows PowerShell 1.0 を先にインストールしておけば、SQL Server 2008 Express でも Windows PowerShell で SQL Server を操作できるようになります。 SQL Server PowerShell is an option component in SQL Express 2008. Optional in this case means that we do not make Windows PowerShell 1.0 a prerequisite for SQL Express 2008, but it is required to use the new

Windows Azure, Azure Data Services, SQL Data Services and related cloud computing topics now appear in this weekly series. Note: This post is updated daily or more frequently, depending on the availability of new articles. ••• Updated 3/12-15/2009: More Additions (Amazon EC2 and Rackspace Cloud Servers price war, more S[S]DS updates) • • Updated 3/11/2009: Additions (mostly about the SDS course reversal) • Updated 3/10/2009 to add SQL Data Services Abandons REST

My job as an evangelist focuses on Windows platform (client and Server OS), including management (i.e. PowerShell) and Virtualization. But there are other Microsoft products which from my day to day use of them I feel evangelical about. One is Windows Live Writer which is the best tool for composing blog posts that I’ve found. Word can do blog posts, but somehow writer feels better suited to the task. I used to do a lot with office Communications server (and I’ve written sections for both of

Matt Uyttendaele , from Microsoft Research, contacted me about using PowerShell to transform files for the Microsoft ICE product. Microsoft Image Composite Editor is an advanced panoramic image stitcher which creates multi-resolution tiled formats like HD View and Silverlight Deep Zoom . We went from this To This Matt wanted to convert to Xml, laying out nodes for the file name, X and Y translation and in the process apply the scaling factor from the matrix to each coord

 Technorati Search for: PowerShell AND (Cmdlet OR Provider) News Feed 

 Mabsterama : powershell News Feed 
Tuesday, November 06, 2007  |  From Mabsterama : powershell

I'm writing this post from version 12.0.1366.1026 of Windows Live Writer - updated as part of Windows Live Wave 2 of the Windows Live suite of applications, which was released overnight. That includes a new version of Live Messenger, Live Mail, Live Photo Gallery etc.

Also released this week was the first alpha of Paint.NET 3.20. I don't know many people who still don't use Paint.NET, but it's an invaluable addition to Windows if you do any kind of image manipulation. See Rick's blog post for the full list of new features and changes in this version.

And lastly we have the first CTP of PowerShell 2.0! Remember that this is a CTP drop, so it's not for installation on production machines. See Jeffrey's post about CTPs if you're not sure.

Tuesday, January 09, 2007  |  From Mabsterama : powershell

In my last post I described a way to list out all your subscribed feeds that haven't been posted to in four months. This works well, but leaves it up to you to do something with those feeds.

The next logical step is to let PowerShell worry about them. That is, have the script itself automatically delete the feeds, or perhaps move them to a "Dead" folder for you to keep an eye on.

Now, the current version the PowerShell Community Extensions does not have a FeedStoreProvider that supports the "move-item" command, but that'll change soon (I've already written the code). In the meantime, here's how you'd delete the old feeds:

cd feed:\
gci -rec |
	?{ $_.Type -eq "Feed" } | 
	%{ $_.Items | sort -desc PubDate | select -first 1 } |
	?{ $_.PubDate -lt [DateTime]::Now.AddMonths(-4)
		-and $_.PubDate.Year -gt 1899} |
	%{ $_.Parent } |
	remove-item -recurse

Note the "-recurse" parameter on remove-item. That's because feeds are technically containers (they contain feed items), so unless you specify the "-recurse" parameter you will be prompted to delete each feed.

Next, here's how you'd move the old feeds to a "Dead" folder:

cd feed:\
new-item -itemType Folder Dead

gci -rec |
	?{ $_.Type -eq "Feed" } | 
	%{ $_.Items | sort -desc PubDate | select -first 1 } |
	?{ $_.PubDate -lt [DateTime]::Now.AddMonths(-4)
		-and $_.PubDate.Year -gt 1899} |
	%{ $_.Parent } |
	move-item -destination \Dead

One small caveat: You have to be sitting in the root of your "feed:" drive for this to work. The reason for this is that remove-item and move-item both look for a "Path" property on the item that gets piped through to them, and for feeds the "Path" property is a relative path from the root folder (eg. "Blogs\Mabsterama"). So the commands won't find the item to remove or move unless you're currently sitting in "feed:\".

Tuesday, January 09, 2007  |  From Mabsterama : powershell

With the new year well and truly underway, it's time to go over all those RSS feeds you're subscribed to, and clean out the ones that don't get updated any more.

But how? How could you possibly know which feeds haven't been posted to in the past, say, four months?

Why - with Windows PowerShell, of course! With a little help from the PowerShell Community Extensions and its awesome Common Feed Store provider!

So here's the command:

gci feed:\ -rec |
	?{ $_.Type -eq "Feed" } | 
	%{ $_.Items | sort -desc PubDate | select -first 1 } |
	?{ $_.PubDate -lt [DateTime]::Now.AddMonths(-4)} | 
	select @{Name="Feed" Expression={$_.Parent.Name}}, PubDate |
	ft -au

... and here's the result on my home PC:

Feed                 PubDate
----                 -------
DataWorks WebLog     12/07/2006 7:57:00 AM
Smart Client Data    9/08/2006 8:10:00 PM
What's in Store      27/06/2006 1:26:00 PM
Mick's Mix           21/08/2006 9:07:00 PM
Microsoft at Home    20/06/2006 6:00:00 PM
Microsoft at Work    9/05/2006 6:00:00 PM
Xbox World Australia 30/12/1899 12:00:00 AM
DVD Plaza            30/12/1899 12:00:00 AM
Luke Hutteman        9/01/2006 5:12:37 AM
Microsoft at Home    20/06/2006 6:00:00 PM
Microsoft at Work    9/05/2006 6:00:00 PM

Notice that a couple of those feeds have a date in 1899. That means that they don't provide a date against their posts, so they can be ignored - might as well keep hold of 'em. The rest can go! Ah ... a fresh start. :)

Tuesday, December 12, 2006  |  From Mabsterama : powershell

Here's a little one-liner to list out your all your Internet Explorer favorites:

gci $env:userprofile\favorites -rec -inc *.url |
    ? {select-string -inp $_ -quiet "^URL=http"} |
    select @{Name="Name"; Expression={[IO.Path]::GetFileNameWithoutExtension($_.FullName)}},
        @{Name="URL"; Expression={get-content $_ | ? {$_ -match "^URL=http"} | % {$_.Substring(4)}}}

Monday, December 11, 2006  |  From Mabsterama : powershell

Keith Hill has just announced the official 1.0 release of the PowerShell Community Extensions. This is a collection of handy cmdlets and functions for Windows PowerShell, and includes my provider for the Windows RSS Platform common feed store (which gives you a "feed:" drive on Vista, or if you have IE7 or Outlook 2007 installed).

Go grab it!

Tuesday, November 14, 2006  |  From Mabsterama : powershell

The official "RTW" (release to web) version of Windows PowerShell is now available! Check out the Windows PowerShell Team Blog for more details and download links.

This release is actually identical to the RC2 release, except with a new installer and licence agreement. The guys obviously did such a good job with RC2 that nothing needed to change. My FeedStoreProvider still works just fine without being recompiled or anything.

Well done, guys!

Wednesday, November 08, 2006  |  From Mabsterama : powershell

Another month and another AWDNUG meeting, and if you missed this one you should be kicking yourself.

Michael from Border Express gave an excellent presentation about SQL Server replication, breaking down the different types of replication, the pros and cons of each type, and how (and what) to monitor them. He also touched on some query optimization tips which I think were appreciated by everyone.

Did you know that if you select a table name in Sql Server Management Studio and hit Alt+F1 it dumps the table structure to the query results? I didn't either.

We had about 20 minutes left over after Michael's presentation (did I mention it was excellent?), so I gave a quick introduction to Windows PowerShell. There really wasn't enough time to touch on all the things that PowerShell is capable of, and I didn't have anything prepared, but I hope that those present got an idea of just how amazing this little command-line engine is.

The turn-out this month was less than spectacular, but I'm sure that all those who didn't attend will read this post and realised that they can't afford to miss any more meetings! See you in December, guys!

Wednesday, October 25, 2006  |  From Mabsterama : powershell

Keith and co over at the PowerShell Community Extensions project has released an alpha version, which gives you some neat new commands like "get-clipboard" and "set-filedate" in PowerShell.

The next version will include my Common Feed Store provider!

So anyway, head on over to CodePlex and download the first alpha - the guys have done a great job with the install and the cmdlets so far are worthwhile.

Monday, October 23, 2006  |  From Mabsterama : powershell

I'm going nuts coming up with new and exciting command-lines to interrogate the common feed store using my new PowerShell provider. Check this one out:

    cd feed:
    dir -rec | 
        where {$_.Author.Length -gt 0} |
        group Author |
        sort Count -desc |
        select -first 20 Name, Count |
        ft -au

That'll get you the top 20 authors across your entire feed list. Note that this is not looking for the feeds with the most items - it's the authors, so if one author posts to more than one feed then he's counted in both places. That said, in my feeds at work Robert Scoble is winning by a mile:

	Name              Count
	----              -----
	Robert Scoble       156
	Zonk                 63
	mabster              60
	Michael S. Kaplan    53
	daveburke            52
	Jason Haley          44
	Cyrus Farivar        44
	kdawson              42
	crucible             42
	Mitch Denny          40
	Leon Bambrick        36
	Paul Miller          33
	bsimser              32
	GregLow              31
	ieblog               31
	oldnewthing          31
	Long Zheng           31
	Darren Murph         30
	Carl Franklin        29
	Daniel Moth          28

Monday, October 23, 2006  |  From Mabsterama : powershell

The latest stuff I've been playing with in my PowerShell FeedStoreProvider is the ability to create and delete items within the store.

So now you can do this:

    # create a new folder called "Mad Props"
    new-item -name "Mad Props" -type folder
    # create a new feed withing that folder
    cd "Mad Props"
    new-item -name Mabsterama -type feed
        -value http://www.madprops.org/cs/blogs/mabster/rss.aspx

Similarly, "remove-item" works too. You can delete a feed or folder like this:

    remove-item Mabsterama

Next thing I want to get working is support for the "-whatif" parameter. In PowerShell you can pass "-whatif" to any command that might do something dangerous (like remove-item) and it'll inform you of what it would have done without actually doing anything. Nice.

Sunday, October 22, 2006  |  From Mabsterama : powershell

Finally worked the last annoying bug out of my FeedStoreProvider for Windows PowerShell yesterday. If you're interested, I was passing an integer as the first parameter to WriteItemObject() from within my GetChildNames override, and it was causing grief. Always pass strings from there, people!

Anyway, here's my latest trick. Want some stats about your feed subscriptions?

    cd feed:
    gci -recurse |
        where {$_ -is [Microsoft.Feeds.Interop.IFeed]} |
        Measure-Object ItemCount -sum -av -min -ma

So we're getting all the child items on my "feed:" drive recursively, filtering the list so that we're only talking about feeds and not folders or feed-items, then getting some statistics from the list. The result on my home box:

    Count    : 87
    Average  : 93.551724137931
    Sum      : 8139
    Maximum  : 200
    Minimum  : 2
    Property : ItemCount

So, I'm subscribed to 87 feeds here, with a total of 8139 items. On average, each feed has about 93 items.

Incidentally, I've added a custom parameter to "get-childitem" called "-unread", so you can, if you desire, list out only unread stuff in your subscriptions. That is, folders that contain feeds with unread items, feeds with unread items, and unread feed items. Very handy!

Friday, October 20, 2006  |  From Mabsterama : powershell

After my success yesterday in accessing the Common Feed Store from PowerShell, I started to wonder just how difficult it would be to write a provider for PowerShell so that I could access my feeds as if they were folders and files. You see, in PowerShell, you're not limited to hard drives and files when you use "dir", "cd" etc - you can change into the Windows Registry, or into the certificate store ... all sorts of places.

So I did some reading on MSDN about creating your own PowerShell providers.

A few hours later, and I can now do this:

    cd feed:
    dir -recurse |
        where {$_.Modified -gt [DateTime]::Now.AddMinutes(-90)} |
        ft Title

... which yields this output:

Title
-----
Opening & Saving Word, PowerPoint and Excel 2...
Niche Player No More;  Apple in the running f...
Where's the Cowboy Talk Now?
Open Source Music Software & The AGNULA Proje...
Zelda:Twilight Princess for GameCube NOT to b...
Old buddies reunite in hopes of taking tech w...
Fifteen Exercises for Learning a new Programm...
LOST - Further Instructions Recap

Engadget's relaunch giveaways: Slingbox PRO w...

In other words, I can list out from the command-line all the items in my feeds that have been updated in the last 90 minutes!

I'll keep working on this provider to give it more functionality. For example, right now you can't use wildcards when you type "dir", and there is no default formatting for feeds, so you need to pipe everything through to format-table to get a nice output. Still, not bad for a few hours' work!!!

Thursday, October 19, 2006  |  From Mabsterama : powershell

Oh, this is just too much fun. Check this out - a PowerShell script to display the feeds you're subscribed to (in the common RSS store you get with IE7) which have unread items:

    $feeds = (new-object -ComObject Microsoft.FeedsManager); 
    % { 
        $feeds.RootFolder.Subfolders | 
            % {$_.Feeds} | 
            select-object -pr UnreadItemCount, Title; 
        $feeds.RootFolder.Feeds | 
            select-object -pr UnreadItemCount, Title 
    } | where {$_.UnreadItemCount -gt 0} | format-table -au

I haven't found a "nice" way to combine the output of two commands into one array, but just executing both together inside a scriptblock like this appears to work.

What do you think? It's amazing the sort of stuff you can do in PowerShell!

Update! You can combine the results of two commands into a single array! Here's an updated script:

    $feeds = (new-object -ComObject Microsoft.FeedsManager); 
    @( 
        $feeds.RootFolder.Subfolders |
            % {$_.Feeds} |
            select-object -pr UnreadItemCount, Title;
        $feeds.RootFolder.Feeds | 
            select-object -pr UnreadItemCount, Title 
    ) | where {$_.UnreadItemCount -gt 0} | format-table -au

And here's the output on my machine right now:

    UnreadItemCount Title
    --------------- -----
                  4 digg
                  1 Slashdot

Wednesday, October 18, 2006  |  From Mabsterama : powershell

For the past few days I've been messing around with Windows PowerShell. PowerShell is the next-generation command-line environment for Windows and associated server products (for example, Exchange 2007 will use it as a command-line and scripting interface). It's way beyond anything you've used in a command-line in the past, because instead of passing text from command to command (via a pipeline) you're passing fully-fledged .NET objects.

Let me give you an example!

Let's say you want to know some statistics about lines of code in your source tree. The first thing you need to get is a list of C# files on your drive. No problem:

get-childitem \ -recurse -include *.cs

What are we doing here? Well, first we're using the get-childitem to recursively list every file on our hard drive with an extension of ".cs". The output of get-childitem is not a simple string of text - it's an array of System.IO.FileInfo classes.

So now we need information about the contents of each of those files. How many lines are in each file? Let's pipe our output through to another command:

dir \ -recurse -include *.cs | get-content

The get-content command returns the contents of a file as an array of strings, one for each line. We want to get the length of that array (the number of lines in the file), so let's use that get-content call in a slightly different way:

dir \ -recurse -include *.cs | 
    select-object @{Name="Lines"; Expression={(get-content $_).Length}}

The select-object command selects certain properties from the given object (in this case the FileInfo objects in the array returned by "get-childitem"). We're returning a calculated property called "Lines" which is the number of lines in the file (based on the length of the array returned by get-content).

So now our command is returning an array of Int32 values - the number of lines in every C# file on our hard drive. Last thing we want to do is get some statistics about those numbers:

dir \ -recurse -include *.cs | 
    select-object @{Name="Lines"; Expression={(get-content $_).Length}} | 
    measure-object Lines -av -sum -max -min

And we're done! The measure-object command gives us all the statistics we need. Here's an example of the output from the above string of commands:

Count : 63
Average : 221.587301587302
Sum : 13960
Maximum : 8425
Minimum : 20
Property : Lines

Pretty cool, huh? One line of commands to get a bunch of handy statistics about your lines-of-code.

This is a really simple breakdown of what's possible in PowerShell. Check out the team blog for a more in-depth look at the amazing things this thing is capable of!

 Mabsterama : powershell News Feed 

Last edited Dec 7, 2006 at 10:16 PM by codeplexadmin, version 1

Comments

No comments yet.