# Monday, July 26, 2010

Write your own PowerShell provider using only script, no C# required. Module definition is provided by a Windows PowerShell 2.0 Module, which may be pure script, binary or a mix of both.

Debugging is as easy as any ordinary ps1 script file:

image

All functions in backing module reflect the same signature as those found on MSDN. This means that you go to MSDN documentation on providers to learn about how to write the corresponding script.

Current Release PSProvider 0.4

Samples and Templates

Roadmap

0.1
  • ContainerCmdletProvider support through "ModuleBoundProvider" provider
  • Demo provider included navigating a Hashtable
  • Can be debugged in the debugger of your choice: console, ISE, PowerGUI.
0.2
  • NavigationCmdletProvider support
  • Providers rename to ContainerScriptProvider and TreeScriptProvider
  • Container Sample & Tree Template modules
  • Supports: Clear-Item, Copy-Item, Get-Item, Invoke-Item, Move-Item, New-Item, Remove-Item, Rename-Item, Set-Item
0.3
  • IContentCmdletProvider support
  • New Commands: New-ContentReader, New-ContentWriter implement IContentReader, IContentWriter
  • Adds support for: Add-Content, Clear-Content, Get-Content, Set-Content
0.4 (Current Release)
  • IPropertyCmdletProvider support
  • Adds support for: Clear-ItemProperty, Copy-ItemProperty, Get-ItemProperty, Move-ItemProperty, New-ItemProperty, Remove-ItemProperty, Rename-ItemProperty, Set-ItemProperty
0.5
  • Dynamic Parameter support
0.6
  • Security Interfaces
  • Adds support for: Get-ACL, Set-ACL

http://psprovider.codeplex.com/

posted on Monday, July 26, 2010 5:33:21 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [1] Trackback
# Wednesday, May 05, 2010

This is a lot of fun if you spend a lot of time tinkering around with APIs in PowerShell. This function (included in the upcoming PSCX 2.0, alias: refl) will let you open Lutz Roeder’s Reflector for any Type or Cmdlet. Reflector will automatically load the correct Assembly and will highlight the relevant Type, without you having to do diddley-squat. Examples and help will display with -?

function Invoke-Reflector {
<#
    .SYNOPSIS
        Quickly load Reflector, with the specified Type or Command selected.
    .DESCRIPTION
        Quickly load Reflector, with the specified Type or Command selected. The function will also
        ensure that Reflector has the Type or Command's containing Assembly loaded.
    .EXAMPLE
        # Opens System.String in Reflector. Will load its Assembly into Reflector if required.
        ps> [string] | invoke-reflector
    .EXAMPLE
        # Opens GetChildItemCommand in Reflector. Will load its Assembly into Reflector if required.
        ps> gcm ls | invoke-reflector
    .EXAMPLE
        # Opens GetChildItemCommand in Reflector. Will load its Assembly into Reflector if required.
        ps> invoke-reflector dir
    .PARAMETER CommandName
        Accepts name of command. Does not accept pipeline input.
    .PARAMETER CommandInfo
        Accepts output from Get-Command (gcm). Accepts pipeline input.
    .PARAMETER Type
        Accepts a System.Type (System.RuntimeType). Accepts pipeline input.
    .PARAMETER ReflectorPath
        Optional. Defaults to Reflector.exe's location if it is found in your $ENV:PATH. If not found, you must specify.
    .INPUTS
        [System.Type]
        [System.Management.Automation.CommandInfo]
    .OUTPUTS
        None
#>
     [cmdletbinding(defaultparametersetname="name")]
     param(
         [parameter(
            parametersetname="name",
            position=0,
            mandatory=$true
         )]
         [validatenotnullorempty()]
         [string]$CommandName,

         [parameter(
            parametersetname="command",
            position=0,
            valuefrompipeline=$true,
            mandatory=$true
         )]
         [validatenotnull()]
         [management.automation.commandinfo]$CommandInfo,

         [parameter(
            parametersetname="type",
            position=0,
            valuefrompipeline=$true,
            mandatory=$true
         )]
         [validatenotnull()]
         [type]$Type,

         [parameter(
            position=1
         )]
         [validatenotnullorempty()]
         [string]$ReflectorPath = $((gcm reflector.exe -ea 0).definition)
     )

        # no process block; i only want
        # a single reflector instance

        if ($ReflectorPath -and (test-path $reflectorpath)) {

            $typeName = $null
            $assemblyLocation = $null

            switch ($pscmdlet.parametersetname) {

                 { "name","command" -contains $_ } {

                    if ($CommandName) {
                        $CommandInfo = gcm $CommandName -ea 0
                    } else {
                        $CommandName = $CommandInfo.Name
                    }

                    if ($CommandInfo -is [management.automation.aliasinfo]) {

                        # expand aliases
                        while ($CommandInfo.CommandType -eq "Alias") {
                            $CommandInfo = gcm $CommandInfo.Definition
                        }
                    }

                    # can only reflect cmdlets, obviously.
                    if ($CommandInfo.CommandType -eq "Cmdlet") {

                        $typeName = $commandinfo.implementingtype.fullname
                        $assemblyLocation = $commandinfo.implementingtype.assembly.location

                    } elseif ($CommandInfo) {
                        write-warning "$CommandInfo is not a Cmdlet."
                    } else {
                        write-warning "Cmdlet $CommandName does not exist in current scope. Have you loaded its containing module or snap-in?"
                    }
                }

                "type" {
                    $typeName = $type.fullname
                    $assemblyLocation = $type.assembly.location
                }
            } # end switch


            if ($typeName -and $assemblyLocation) {
                & $reflectorPath /select:$typeName $assemblyLocation
            }

        } else {
            write-warning "Unable to find Reflector.exe. Please specify full path via -ReflectorPath."
        }
}

Have fun!

posted on Wednesday, May 05, 2010 5:05:16 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] Trackback
# Monday, May 03, 2010

These days I'm incredibly busy both in my professional and private life, so I’ve not had a lot of time to construct the usual meaty posts I like to write. Instead I figured I could write a series of short – very short – posts centered around the little tricks that you would need to be an efficient developer when targeting PowerShell. Here's the first tip: how to create a Runspace and have one or more Module(s) preloaded. The RunspaceInvoke class is a handy wrapper that will do most of the plumbing for you if you just want to run scripts or commands. If you want to manually construct your own Pipeline instances then you must work with the Runspace class directly.

    InitialSessionState initial = InitialSessionState.CreateDefault();
    initialSession.ImportPSModule(new[] { modulePathOrModuleName1, ... });
    Runspace runspace = RunspaceFactory.CreateRunspace(initial);
    runspace.Open();
    RunspaceInvoke invoker = new RunspaceInvoke(runspace);
    Collection<PSObject> results = invoker.Invoke("...");

Have fun!

posted on Monday, May 03, 2010 12:54:13 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] Trackback
# Wednesday, March 10, 2010

This is unashamedly a post for developers, in particular those with an interest in functional languages. With the advent of PowerShell 2.0, some of you may have noticed that ScriptBlocks - which I suppose could also be called anonymous functions or lambdas - gained a new method: GetNewClosure. Closures are one of the essential tools for functional programming., something I’ve been trying to learn more about over the last few years. I don’t really have an opportunity to use it in work other than the hybrid trickery available in C# 3.0, but I have been tinkering a lot with PowerShell 2.0 to see if some of the tricks of the functional trade could be implemented. It’s just a shell language, but there are some nice features in there that enable a wide variety of funky stuff.

Partial Application

In a nutshell, partial application of a function is when you pass in only some of the parameters and get a function back that can accept the remaining parameters:

# define a simple function
function test {
    param($a, $b, $c);
    "a: $a; b: $b; c:$c"
}

# partially apply with -c parameter
$f = merge-parameter (gcm test) -c 5

# partially apply with -c and -a then execute with -b (papp is an alias)
& (papp (papp (gcm test) -c 3) -a 2) -b 7

# partially apply the get-command cmdlet with -commandtype
# and assign the result to a new function
si function:get-function (papp (gcm get-command) -commandtype function)

This is by no means a complete implementation of a partial application framework for powershell. The merge-parameter function (aliased to papp) currently only works with the default parameterset and does not mirror any of the parameteric attributes in the applied function or cmdlet. I'm not saying it couldn't do that, but this is purely a proof of concept. The module is listed below and is also available from PoshCode at http://poshcode.org/1687

# save as functional.psm1 and drop into your module path
Set-StrictMode -Version 2

$commonParameters = @("Verbose",
                      "Debug",
                      "ErrorAction",
                      "WarningAction",
                      "ErrorVariable",
                      "WarningVariable",
                      "OutVariable",
                      "OutBuffer")

<#
.SYNOPSIS
    Support function for partially-applied cmdlets and functions.
#>
function Get-ParameterDictionary {
    [outputtype([Management.Automation.RuntimeDefinedParameterDictionary])]
    [cmdletbinding()]
    param(
        [validatenotnull()]
        [management.automation.commandinfo]$CommandInfo,
        [validatenotnull()]
        [management.automation.pscmdlet]$PSCmdletContext = $PSCmdlet
    )
    
    # dictionary to hold dynamic parameters
    $rdpd = new-object Management.Automation.RuntimeDefinedParameterDictionary

    try {
        # grab parameters from function
        if ($CommandInfo.parametersets.count > 1) {
            $parameters = $CommandInfo.ParameterSets[[string]$CommandInfo.DefaultParameterSet].parameters
        } else {
            $parameters = $CommandInfo.parameters.getenumerator() | % {$CommandInfo.parameters[$_.key]}
        }        
                
        $parameters | % {
            
            write-verbose "testing $($_.name)"
                                    
            # skip common parameters        
            if ($commonParameters -like $_.Name) {                                  
                
                write-verbose "skipping common parameter $($_.name)"
                
            } else {
                
                $rdp = new-object management.automation.runtimedefinedparameter
                $rdp.Name = $_.Name
                $rdp.ParameterType = $_.ParameterType
                
                # tag new parameters to match this function's parameterset
                $pa = new-object system.management.automation.parameterattribute
                $pa.ParameterSetName = $PSCmdletContext.ParameterSetName
                $rdp.Attributes.Add($pa)
                
                $rdpd.add($_.Name, $rdp)
            }
            
        }
    } catch {
    
        Write-Warning "Error getting parameter dictionary: $_"
    }
    
    # return
    $rdpd
}

<#
.SYNOPSIS
    Function that accepts a FunctionInfo or CmdletInfo reference and one or more parameters
    and returns a FunctionInfo bound to those parameter(s) and their value(s.)
.DESCRIPTION
    Function that accepts a FunctionInfo or CmdletInfo reference and one or more parameters
    and returns a FunctionInfo bound to those parameter(s) and their value(s.)
    
    Any parameters "merged" into the function are removed from the available parameters for
    future invocations. Multiple chained merge-parameter calls are permitted.
.EXAMPLE

    First, we define a simple function:
    
    function test {
        param($a, $b, $c, $d);
        "a: $a; b: $b; c:$c; d:$d"
    }
    
    Now we merge -b parameter into functioninfo with the static value of 5, returning a new
    functioninfo:
    
    ps> $x = merge-parameter (gcm test) -b 5
    
    We execute the new functioninfo with the & (call) operator, passing in the remaining 
    arguments:
    
    ps> & $x -a 2 -c 4 -d 9
    a: 2; b: 5; c: 4; d: 9
    
    Now we merge two new parameters in, -c with the value 3 and -d with 5:
    
    ps> $y = merge-parameter $x -c 3 -d 5
    
    Again we call $y with the remaining named parameter -a:
    
    ps> & $y -a 2
    a: 2; b: 5; c: 3; d: 5
.EXAMPLE

    Cmdlets can also be subject to partial application. In this case we create a new
    function with the returned functioninfo:
    
    ps> si function:get-function (merge-parameter (gcm get-command) -commandtype function)
    ps> get-function
                
.PARAMETER _CommandInfo
    The FunctionInfo or CmdletInfo into which to merge (apply) parameter(s.)
    
    The parameter is named with a leading underscore character to prevent parameter
    collisions when exposing the targetted command's parameters and dynamic parameters.
.INPUTS
    FunctionInfo or CmdletInfo
.OUTPUTS
    FunctionInfo
#>
function Merge-Parameter {    
    [OutputType([Management.Automation.FunctionInfo])]
    [CmdletBinding()]
    param(
        [parameter(position=0, mandatory=$true)]
        [validatenotnull()]
        [validatescript({
            ($_ -is [management.automation.functioninfo]) -or `
            ($_ -is [management.automation.cmdletinfo])
        })]
        [management.automation.commandinfo]$_Command
    )
    
    dynamicparam {
        # strict mode compatible check for parameter
        if ((test-path variable:_command)) {
            # attach input functioninfo's parameters to self
            Get-ParameterDictionary $_Command $PSCmdlet
        }
    }

    begin {
        write-verbose "merge-parameter: begin"
        
        # copy our bound parameters, except common ones              
        $mergedParameters = new-object 'collections.generic.dictionary[string,object]' $PSBoundParameters
        
        # remove our parameters, leaving only target function/CommandInfo's args to curry in
        $mergedParameters.remove("_Command") > $null
        
        # remove common parameters
        $commonParameters | % {
            if ($mergedParameters.ContainsKey($_)) {
                $mergedParameters.Remove($_)  > $null
            }
        }
    }
    
    process {
        write-verbose "merge-parameter: process"
        
        # temporary function name
        $temp = [guid]::NewGuid()

        $target = $_Command

        # splat our fixed named parameter(s) and then splat remaining args
        $partial = {
            [cmdletbinding()]
            param()
            
            # begin dynamicparam
            dynamicparam
            {                
                $targetRdpd = Get-ParameterDictionary $target $PSCmdlet
        
                # remove fixed parameters
                $mergedParameters.keys | % {
                    $targetRdpd.remove($_) > $null
                }
                $targetRdpd
            }
            begin {
                write-verbose "i have $($mergedParameters.count) fixed parameter(s)."
                write-verbose "i have $($targetrdpd.count) remaining parameter(s)"
            }
            # end dynamicparam
            process {
                $boundParameters = $PSCmdlet.MyInvocation.BoundParameters
                
                # remove common parameters (verbose, whatif etc)
                $commonParameters | % {
                    if ($boundParameters.ContainsKey($_)) {
                        $boundParameters.Remove($_)  > $null
                    }
                }
                
                # invoke command with fixed parameters and passed parameters (all named)
                . $target @mergedParameters @boundParameters
                
                if ($args) {
                    write-warning "received $($args.count) arg(s) not part of function."
                }
            }
        }
        
        # emit function/CommandInfo
        new-item -Path function:$temp -Value $partial.GetNewClosure()
    }
    
    end {
        # cleanup
        rm function:$temp
    }    
}

new-alias papp Merge-Parameter -force

Export-ModuleMember -Alias papp -Function Merge-Parameter, Get-ParameterDictionary

Have fun[ctional]!

posted on Wednesday, March 10, 2010 8:01:07 PM (Eastern Standard Time, UTC-05:00)  #    Comments [1] Trackback
# Friday, March 05, 2010

Paths in PowerShell are tough to understand [at first.] PowerShell Paths - or PSPaths, not to be confused with Win32 paths - in their absolute forms, come in two distinct flavours:

  • Provider-qualified: FileSystem::c:\temp\foo.txt
  • Drive-qualified: c:\temp\foo.txt

It's very easy to get confused over provider-internal (The ProviderPath property of a resolved PathInfo – and the bold portion of the provider-qualified path above) and drive-qualified paths since they look the same if you look at the default FileSystem provider drives. That is to say, the PSDrive has the same name (C) as the native backing store, the windows filesystem (C). So, to make it easier for yourself to understand the differences, create yourself a new PSDrive:

ps c:\> new-psdrive temp filesystem c:\temp\
ps c:\> cd temp:
ps temp:\>

Now, let's look at this again:

  • Provider-qualified: FileSystem::c:\temp\foo.txt
  • Drive-qualified: temp:\foo.txt

A bit easier this time to see what’s different this time. The bold text to the right of the provider name is the ProviderPath.

So, your goals for writing a generalized provider-friendly Cmdlet (or advanced function) that accepts paths are:

  • Define a LiteralPath path parameter aliased to PSPath
  • Define a Path parameter (which will resolve wildcards / glob)
  • Assume you are receiving PSPaths, NOT native provider-paths

Point number three is especially important. Also, obviously LiteralPath and Path should belong in mutually exclusive parameter sets.

Relative Paths

A good question is: how do we deal with relative paths being passed to a Cmdlet. As you should assume all paths being given to you are PSPaths,  let’s look at what the Cmdlet below does:

ps temp:\> write-zip -literalpath foo.txt

The command should assume foo.txt is in the current drive, so this should be resolved immediately in the ProcessRecord or EndProcessing block like (using the scripting API here to demo):

$provider = $null;
$drive = $null
$providerPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath("foo.txt", [ref]$provider, [ref]$drive)

Now you everything you need to recreate the two absolute forms of PSPaths, and you also have the native absolute ProviderPath. To create a provider-qualified PSPath for foo.txt, use $provider.Name + “::” + $providerPath. If $drive is not null (your current location might be provider-qualified in which case $drive will be null) then you should use $drive.name + ":\" + $drive.CurrentLocation + "\" + "foo.txt" to get a drive-qualified PSPath.

Have fun!

posted on Friday, March 05, 2010 1:02:31 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] Trackback
# Sunday, January 17, 2010

Did you know that when you run Get-Help against a cmdlet to find out about its parameters, you might not be getting the whole truth? Certain cmdlets, especially those that operate on providers (FileSystem, Certificate, Registry etc) can adopt new parameters on the fly, depending on the path they are acting on. For example, when use you Get-Content on the file system (drive c: etc), it gets three new parameters in addition to the static ones listed by Get-Help (but more about this later): Delimiter, Encoding and Wait.

Determining Dynamic Parameters using Get-Help

Get-Help has a new parameter, –Path, which lets you give the help system some context for determining dynamic parameters:

-Path <string>
    Gets help that explains how the cmdlet works in the specified provider path. Enter a Windows PowerShell provider path.

    This parameter gets a customized version of a cmdlet help topic that explains how the cmdlet works in the specified Windows PowerShell provider path. This parameter is effective only for help about a provider cmdlet and only when the provider includes a custom version of the provider cmdlet help topic.

    To see the custom cmdlet help for a provider path, go to the provider path location and enter a Get-Help command or, from any path location, use the Path parameter of Get-Help to specify the provider path. For more information, see about_Providers.

Determining Dynamic Parameters using Get-Command

Get-Command has a new parameter, –ArgumentList, which acts similarly to unveil what dynamic parameters might be attached to a cmdlet for a given parameterset and path/literalpath if available on the chosen cmdlet. I’ve written a simple function that takes a cmdlet name as an argument and will display all of the dynamic parameters available for a cmdlet for each distinct provider:

# this function will pass a drive name in position 0 as an unnamed argument
# most path-oriented cmdlets accept this binding
function Get-DynamicParameter {
    param(        
        [string]$command
    ) 
  
    $parameters = @{}
    get-psdrive | sort -unique provider | % {
        $parameters[$_.provider.name] = gcm $command -args "$($_.name):" | % {
            $c = $_; @($_.parameters.keys) | sort | ? {
                $c.parameters[$_].isdynamic
            }
        }
    }
    $parameters    
}

Example use:

PS> Get-DynamicParameter get-content

Name                           Value
----                           -----
Alias
FileSystem                     {Delimiter, Encoding, Wait}
AssemblyCache
Registry
Environment
WSMan
Certificate
FeedStore
Function
Variable
PscxSettings

NOTE: when you don’t pass any context parameters to get-command via –argumentlist, it will take your current location as the context for dynamic parameters (if any are found.) So running get-command from c:\ instead hklm:\ will give you the additional parameters Delimiter, Encoding and Wait.

Have fun!

posted on Sunday, January 17, 2010 9:33:04 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] Trackback
# Wednesday, October 28, 2009

( from: http://support.microsoft.com/default.aspx/kb/968929 – downloads at foot of page )

Windows PowerShell is a command-line shell and scripting language that is designed for system administration and Automation. Built on the Microsoft .NET Framework, Windows PowerShell enables IT professionals and developers to control and automate the administration of Windows and applications.

New features that are introduced in Windows PowerShell 2.0 include the following:

  • Remoting
    Windows PowerShell 2.0 lets you run commands on one or more remote computers from a single computer that is running Windows PowerShell. PowerShell remoting allows for multiple ways of connecting. These ways include interactive (1:1), fan-out (1:many), and fan-in (many:1 by using the IIS hosting model).
  • Integrated Scripting Environment
    PowerShell Integrated Scripting Environment (ISE) enables you to run interactive commands and edit and debug scripts in a graphical environment. The main features include color-coded syntax, selective execution, graphical debugging, Unicode support, and context-sensitive help.
  • Modules
    Modules allow for script developers and administrators to partition and organize their Windows PowerShell code in self-contained, reusable units. Code from a module executes in its own self-contained context and does not affect the state outside the module.
  • Advanced functions
    Advanced functions are functions that have the same capabilities and behavior as cmdlets. However, they are written completely in the Windows PowerShell language, instead of compiled C#.
  • Background jobs
    Windows PowerShell 2.0 allows for running a command or expression asynchronously and "in the background" without interacting with the console.
  • Eventing
    This feature adds support to the Windows PowerShell engine infrastructure for listening, forwarding, and acting on management and system events.
  • Script internationalization
    This new feature enables Windows PowerShell scripts to display messages in the spoken language that is specified by the UI culture setting on the user's computer.
  • Script debugging
    New debugging features were added to Windows PowerShell that let you set breakpoints on lines, columns, variables, and commands, and that let you specify the action that occurs when the breakpoint is hit.
  • New cmdlets
    Windows PowerShell 2.0 introduces over 100 built-in cmdlets. These cmdlets, excluding other tasks, enables you to do computer-related, event log, and performance counter management tasks.

WinRM 2.0

WinRM is the Microsoft implementation of WS-Management Protocol, a standard Simple Object Access Protocol (SOAP)–based, firewall-friendly protocol that allows for hardware and operating systems from different vendors to interoperate. The WS-Management Protocol specification provides a common way for systems to access and exchange management information across an IT infrastructure.

WinRM 2.0 includes the following new features:

  • The WinRM Client Shell API provides functionality to create and manage shells and shell operations, commands, and data streams on remote computers.
  • The WinRM Plug-in API provides functionality that enables a user to write plug-ins by implementing certain APIs for supported resources and operations.
  • WinRM 2.0 introduces a hosting framework. Two hosting models are supported. One is Internet Information Services (IIS)-based and the other is WinRM service-based.
  • Association traversal lets a user retrieve instances of Association classes by using a standard filtering mechanism.
  • WinRM 2.0 supports delegating user credentials across multiple remote computers.
  • Users of WinRM 2.0 can use Windows PowerShell cmdlets for system management.
  • WinRM has added a specific set of quotas that provide a better quality of service and allocate server resources to concurrent users. The WinRM quota set is based on the quota infrastructure that is implemented for the IIS service.

System requirements

WinRM 2.0 and PowerShell 2.0 can be installed on the following supported operating systems:

  • Windows Server 2008 with Service Pack 2
  • Windows Server 2003 with Service Pack 2
  • Windows Vista with Service Pack 2
  • Windows Vista with Service Pack 1
  • Windows XP with Service Pack 3
Windows PowerShell 2.0 requires the Microsoft .NET Framework 2.0 with Service Pack 1.

BITS 4.0

BITS 4.0 can be installed on the following supported operating systems:
  • Windows Server 2008 with Service Pack 2
  • Windows Vista with Service Pack 2
  • Windows Vista with Service Pack 1
posted on Wednesday, October 28, 2009 9:27:29 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] Trackback
# Saturday, July 18, 2009

update: missing backtick ` to escape the $verbosepreference variable

A question came up on stack overflow (you don’t know what that is? shame on you!) today from someone asking how they could capture the Verbose stream from a pipeline they ran in a C# program. As it turns out, the same technique is used in script, so I’ll give that example instead since I’m sure the C# guys and gals will have no problem converting the script.

The key is using the new (to v2.0) System.Management.Automation.PowerShell Type, which has a built-in Type Accelerator of [powershell]. It has a static method, Create, which is used to create an instance. This instance is pretty much ready to roll. It has a Streams property, which is of Type PSDataStreams. This Type has properties representing each collection of Error, Progress, Verbose, Debug and Warning.

$ps = [powershell]::create()
$ps.Commands.AddScript("`$verbosepreference='continue'; write-verbose 42")
$ps.invoke()
$ps.streams.verbose
Which yields the VerboseRecord that was written out:
Message InvocationInfo                              PipelineIterationInfo
------- --------------                              ---------------------
42      System.Management.Automation.InvocationInfo {0, 0}
What's important to note about the above example is that I had to set the $verbosepreference to at least "continue" (the default is silentlycontinue) in order for the verbose record to be written. Have fun!
posted on Saturday, July 18, 2009 12:02:53 AM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] Trackback
# Friday, May 22, 2009

update #1 2009/5/23: noted that local jobs (start-job) no longer require an elevated shell.

update #2 2009/5/28: ISE object model and shortcut changes; update for set-psessionconfiguration cmdlet (new screenshot); module changes (highlighted new manifest member names, binary module can now be root module);

I’ve been meaning to write this for a while, but it’s been a busy time. This is a comparison of the significant differences between the standalone CTP3 or Windows 7 Beta version and the version that comes with Win7 RC (6.1.7100.0). For all intents and purposes, the CTP3 version (6.1.6469.0) is exactly the same as the Windows 7 Beta (6.1.7000.0) version.

This is not going to be an exhaustive list of differences, but I will continue to update this post as I find more things worth documenting. It should be safe to bookmark the permalink. One of the nicest things about this release is that it appears that, without exception, all built-in Cmdlets have help. A lot of things have been cleaned up and fixed in this build, from formatting of text to typos and minor bugs/glitches.

Cmdlet Differences

This is a table listing Cmdlets that have either changed (navy), been added (green, underlined) or removed (red, strike-through.) Changed Cmdlets have their parameters listed in the second column. A changed parameter means that its Type has been changed; e.g. it accepts a different .NET object than before. This is generally nothing to worry about since the corresponding source of such objects is usually changed to match – typically another Cmdlet. Parameters  and Cmdlets that have not changed, are not listed.

Cmdlet Parameters
Invoke-Command
Remove-Computer
Add-Computer
Rename-Computer
Test-Connection
Export-FormatData
Receive-Job
Start-Job
Get-Module
New-ModuleManifest
Set-PSBreakpoint
Enable-PSRemoting
Remove-PSSession
Enter-PSSession
New-PSSession
Export-PSSession
Import-PSSession
New-PSSessionOption
Get-WSManInstance
Set-PSSessionConfiguration ShowSecurityDescriptorUI

Alias Changes

Some tweaking of aliases here. Personally I find alias changes in general to get under my skin. Aliases are the first thing I learn and the first thing to trip me up when things change. Regardless, the changes appear to make sense and are perhaps a bit more mnemonic than before.

Removed

emm (Export-ModuleMember), which (Get-Command) and grid (Out-Gridview)

Added

ise (powershell_ise.exe), rmo (Remove-Module) and saps (Start-Process)

Changed

imo –> ipmo (Import-Module)

Language Enhancements

The major change that has come to light so far is that statements are now allowed on the right hand of an expression without having to use subexpressions. This is a great fix, and one that will reduce the margin for error (and confusion) by a large amount. Previously in CTP3, in order to use a statement like “if”, you had to use the following syntax:

$result = $( if ($true) { 42 } )

Now, you can drop the $( and ):

$result = if ($true) { 42 }

or

$sequence = foreach ($i in 0..15) { [math]::pow(2, $i) }

This is truly great stuff.

Jobs/Remoting

The best news here is the abundant help now available at your fingertips. Lots of examples and meaty information concerning PSSessions and PSSessionConfigurations.

Local Jobs

Local jobs created now with Start-Job { ... } use an IPC channel to talk to the local WinRM service to create jobs instead of using the more heavyweight HTTP channel. Yes, you can infer from this that local jobs are still out of process; they run in their own isolated runspace and have no access to the interactive session. What this means in simpler terms is that local jobs are a lot faster now to get started. The biggest win for local jobs is that they no longer require an elevated shell! you can submit local jobs as a regular user now – just not remote ones (unless the applicable remote PSSessionConfiguration is set to allow this - by default the ACL is admins only).

Remoting

A welcome addition to this build is a new, dedicated Enable-PSRemoting Cmdlet:

The Enable-PSRemoting cmdlet configures the computer to receive Windows PowerShell remote commands that are sent by using the WS-Management technology.

You need to run this command only once on each computer that will receive commands. You do not need to run it on computers that only send commands. Because the configuration activates listeners, it is prudent to run it only where it is needed.

The Enable-PSRemoting cmdlet performs the following operations:

  • Runs the Set-WSManQuickConfig cmdlet, which performs the following tasks:
    • Starts the WinRM service.
    • Sets the startup type on the WinRM service to Automatic.
    • Creates a listener to accept requests on any IP address.
    • Enables a firewall exception for WS-Management communications.
  • Enables all registered Windows PowerShell session configurations to receive instructions from a remote computer.
    • Registers the "Microsoft.PowerShell" session configuration, if it is not already registered.
    • Registers the "Microsoft.PowerShell32" session configuration on 64-bit computers, if it is not already registered.
    • Removes the "Deny Everyone" setting from the security descriptor for all the registered session configurations.
    • Restarts the WinRM service to make the preceding changes effective.

To run this cmdlet on Windows Vista, Windows Server 2008, and later versions of Windows, you must start Windows PowerShell with the "Run as administrator" option.

Session Configurations

There are a raft of Cmdlets dedicated to managing session configurations. So what is a session configuration? To qoute the ever-present help system:

A session configuration is a group of settings on the local computer that define the environment for the Windows PowerShell sessions that are created when remote users connect to the local computer.

Administrators of the computer can use session configurations to protect the computer and to define custom environments for users who connect to the computer.

Administrators can also use session configurations to determine the permissions that are required to connect to the computer remotely. By default, only members of the Administrators group have permission to use the session configuration to connect remotely, but you can change the default settings to allow all users, or selected users, to connect remotely to your computer.

Session configurations are a feature of Web Services for Management (WS-Management) based Windows PowerShell remoting. They are used only when you use the New-PSSession, Invoke-Command, or Enter-PSSession cmdlets to connect to a remote computer.

Note: To manage the session configurations on a computer that is running Windows Vista, Windows Server 2008, or a later version of Windows, start Windows PowerShell with the "Run as administrator" option.

image

That SecurityDescriptorSddl property looks like a lot of fun to modify, right? Don’t worry, the ShowSecurityDescriptorUI comes to the rescue:

image

Modules

Manifest Members

Modules have received some nice incremental improvements as well as some syntactic changes. You should have noticed above that the manifest fields (exposed as parameters on New-ModuleManifest)  have changed to reflect the two-stage process of how a module’s members get exposed to the importer’s scope. A module passively exports members with Export-ModuleMember, and the caller actively imports them with Import-Module; hence “FunctionsToExport,” which subtly says that this can be imported.

Binary Modules

A binary module is now allowed to be the root module in a manifest by pointing the ModuleToProcess key at the assembly, e.g. ModuleToProcess = “Pscx.dll.” This seems more intuitive than before with the [seemingly] arbitrary restriction that they must be secondary to a text based psm1.

Built-In Modules

Shipping with Windows 7 for PowerShell comes two new Modules along with the others you should have noticed that arrived with CTP3 (BitsTransfer/FileTransfer and PSDiagnostics.)

AppLocker

AppLocker provides simple, powerful, rule-based structures for specifying which applications can run that are centrally managed using Group Policy. It introduces "publisher rules" that are based on an application's digital signature, making it possible to build strong rules that account for application updates. For example, an organization can create a rule to "allow all versions greater than 1.0 of Microsoft Dynamics CRM to run if signed by Microsoft." With correctly structured rules, IT professionals can safely deploy updates to allowed applications without having to build a new rule for each version update.

About AppLocker on TechNet

TroubleshootingPack

Windows Troubleshooting Platform (WTP) provides ISVs, OEMs, and administrators the ability to write troubleshooting packs that discover and resolve software and hardware issues, such as configuration issues, failed hardware, network issues, and application compatibility issues. In WTP, an issue is referred to as a root cause. Previously, troubleshooting software and hardware issues was a manual process; however, using WTP you can automate the process of fixing the most common issues that the user might encounter.

About WTP on MSDN

PowerShell Integrated Scripting Environment

The ISE has been vastly improved in terms of usability and sharpness in this build. Difficult to isolate any one part of it that is much better; the whole experience is just way smoother and intuitive.

image

ISE Object Model

The object model naming has changed quite a bit to be more intuitive and friendly to beginners. Who needs to know about Runspaces? It’s a Tab, silly!

CTP3 RC
$psise.CurrentOpenedRunspace $psise.CurrentPowerShellTab
$psise.CurrentOpenedRunspace.ToolsMenu $psise.CurrentPowerShellTab.AddOnsMenu
$psise.CurrentOpenedRunspace.OpenedFiles $psise.CurrentPowerShellTab.Files
$psise.CurrentOpenedRunspace.OpenedFiles.RemoveUnsaved($file) $psise.CurrentPowerShellTab.Files.Remove($file,$true)
$psise.OpenedRunspaces $psise.PowerShellTabs
$psise.OpenedRunspaces[1].Execute("string") $psise.PowerShellTabs[1].Invoke({scriptBlock})*
$psise.CurrentOpenedFile $psise.CurrentFile
$psise.Options.LocalHelp $psise.Options.UseLocalHelp

* Note: You may only invoke script on a tab other than the tab you’re using to execute this command (because you can’t run two commands at the same time on the same tab!)

The PowerShell team posted a way to make the RC build fairly compatible with CTP3 by adding new members to the $PSISE object which will proxy attempts to use the old API to the new API. The post is called “Update-TypeData, ISE CTP3 vs ISE RC, and Teched2009 Demos.”

Shortcut Changes

The shortcut to jump to the Script Pane is now Ctrl+I. (use Ctrl+D to jump to the Command pane).

Summary

The RC build is all about bugfixes and incremental improvements. I’m sure there’ll be more fixes and additions as we near RTW/RTM and I’ll be here to post as much info about them as possible. This is still just a drop in the ocean of what PowerShell 2.0 can do, and I’ll post more technical demos of features over the next little while.

Tips: run “Get-Help about_*” to get a list of all the overview topics for the various features in PowerShell v2.

Have fun!

posted on Friday, May 22, 2009 5:25:49 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] Trackback
# Thursday, May 14, 2009

Hey, so we did the unthinkable. We released another version of the PowerShell Community Extensions. We’re calling it a beta, because we’ve be so swamped with Real Life stuff that we’re not 100% confident that it is defect-free. It’s not going to murder your servers or anything, but there might be some documentation missing and other minor stuff. We’d really appreciate it if you can give it a test-drive. If you’re running PowerShell v1.0 or v2.0 CTP3, please use the MSI installer. It will upgrade your Pscx 1.1.1 install if you have one. If, on the other hand, you are running Windows 7 RC and/or have a later version of PowerShell than v2 CTP3, you can download the zipped module and unzip to your user profile module directory at ~\documents\windowspowershell\modules\ and load it using “import-module pscx.”

Thanks for your infinite patience (yes, it’s been a while and we’re sorry) and please leave comments and issues on the tracker at http://pscx.codeplex.com/

View the 1.2 Beta release page.

posted on Thursday, May 14, 2009 8:28:13 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] Trackback
# Thursday, March 19, 2009

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 functions together while allowing easy disambiguation should there be a name collision with another function or cmdlet. It wasn’t always this easy.

Namespaces in PowerShell v1.0

In PowerShell v1.0 it was possible to load two snap-ins that contained identically named commands. This causes PowerShell to spit out an error about ambiguous commands should you try to invoke one. The answer to this was to get the containing snap-in name, and prefix it to the cmdlet name using a backslash as a separator:

$o = Pscx\New-Object Collections.Generic.Dictionary –Of String, Int

As you can see, this lets us call the hypothetical PowerShell Community Extensions version of New-Object to create a generic type. If you want to call the original one, you would have to prefix it like this:

$o = Microsoft.PowerShell.Utility\New-Object Int[] 5

Blech - that’s a bit of a lengthy sentence, but the solution to this is to use an alias. Aliases are found before Cmdlets in the search path:

New-Alias New-Object Microsoft.PowerShell.Utility\New-Object
$o = New-Object Int[] 5 

The reason we need an alias here is because if you just typed the cmdlet without the snap-in prefix, PowerShell v1.0 complains that it doesn’t know which one you want. We forgot to add the mind reader snap-in!

How about functions in PowerShell v1.0? If you dot source a ps1 file that contains functions that already exist in the caller’s session, how do you disambiguate them? Oops! You can’t. They are overwritten. Ouch.

You cannot use the namespace\ prefix for functions in v1 - the support is just not there. However…

Namespaces in PowerShell v2.0

Things are a lot better in this version. Let’s say you have two groups of functions that you use in your business. One for your SharePoint farms, and another set for your Citrix farms. Let’s ignore the perfectly acceptable idea of prefixing the noun to differentiate for the moment and just imagine we have two ps1 files, containing ideally named function with approved verb, simple noun:

# sharepoint functions
function Get-Server {
   # ... gets sharepoint server
}
function Get-Farm {
   # ... gets sharepoint farm
}

And the second script:

# citrix functions
function Get-Server {
    # ... gets citrix server
}
function Get-Farm {
    # ... gets citrix farm
}

If you tried to load these up with via a dot source, one after the other, the functions from the second ps1 would overwrite the first lot. So this is where the wonder world of modules is entered. First step:

After renaming both ps1 files to use the psm1 extension instead, you have created modules of the simplest form. Ignoring the details of how this is deployed (there are several ways – documented on Microsoft and on many blogs, including this one), let's look at how it's loaded and used:

import-module citrix
# Now our functions are loaded. Invocation options:
# assuming no clash, invoke with simple names
get-farm bleh
# load sharepoint module (it also has get-farm)
import-module sharepoint
# ok, sharepoint functions are loaded too, so we have two get-farm commands
# and the last loaded wins, so citrix get-farm is inaccessible through simple syntax, but...
# let's refer specifically to the citrix module function
citrix\get-farm
# and for sharepoint:
sharepoint\get-farm
# and thirdly, if you don't want to use the module qualifier (or "namespace") then you ALSO have the
# choice of applying a prefix on import - this is the primary use case for quick interactive use:
import-module citrix -prefix ctx
# now you can call functions like:
get-ctxfarm
# or even citrix\get-ctxfarm if you so felt like it, but redundant.
# same for sharepoint
import-module sharepoint -prefix sp
get-spfarm

Make sense so far? Unfortunately, as mentioned earlier, in v1.0 the module qualifier (or "namespace") works ONLY for binary commands imported in a Snap-In DLL. Let’s see how that works with get-childitem, a command from one of the preloaded Snap-Ins in PowerShell:

gcm get-childitem | select pssnapin

outputs:

PSSnapIn
--------
Microsoft.PowerShell.Management

Ergo, we invoke it like:
Microsoft.PowerShell.Management\get-childitem
# ... outputs file listing ...

Module Aliasing

Some modules may have longer names that you would be comfortable to type all the time. Thankfully, there is a trick you can do that takes advantage of the fact that modules can be nested. Let’s say you have a module from a vendor that is called something like “Vendor.Division.Product” and it has a cmdlet in it called Get-Thing that happens to clash with another Get-Thing you have loaded. Normally to disambiguate, you have to type:

import-module vendor.division.product
Vendor.Division.Product\Get-Thing

…which is a bit annoying. Instead, wrap the initial import-module statement in a dynamic module where you supply an explicit name for it, and import that instead ;-)

new-module –name product { import-module vendor.division.product } | import-module
# you can now invoke the command like this:
product\get-thing

Any modules that are imported inside a module have their commands automatically exported as if they are part of the root module (unless you control visibility with export-modulemember). Cool, eh?

Have fun!

posted on Thursday, March 19, 2009 10:20:46 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] Trackback
# Tuesday, February 10, 2009

Some of you may have heard that CTP3 has support for transferring files from remote servers using BITS (Background Intelligent Transfer Service) and quite possibly had a little dig around for it. It’s not easy to find as using “get-help BITS” will not return any help unless you’ve already loaded the module. Not a great win for discoverability, but hey, sometimes you just have to read the manual, expletive deleted. So, lets have a quick look at how this works.

image

So, ok, we can see we’ve got a module for FileTransfer (BITS), but where did this come from? Take a peek into $pshome\Modules to find out. This is the location for system-wide (global) modules. It rests under $PSHome, which is the home for PowerShell, in $env:systemroot\windowspowershell\v1.0.

Yes, even PowerShell v2 lives there. This is one of those unfortunate things whereby the team decided early on that they would support side-by-side versions of PowerShell, implying that v2 might not be backwards compatible with v1. This is reflected also in the choice of file extension: ps1. The extension ps2 would have been used for v2. This was probably a poor show of faith in their own abilities to design such a great version one product, because as it turns out, v1.0 was such an excellent release that they were able to build on it for v2 without compromising, or breaking backwards compatibility (apart from a couple of minor edge cases, mainly bugfixes). So, the end result is that future versions of PowerShell will inherit the $pshome, pay a little inheritance tax and hopefully avoid foreclosure :).

The files in the FileTransfer module directory are laid out as follows:

image

(Hey look! another built-in module – PSDiagnostics - I’ll leave that one for you guys to explore).

So, there are four files there. A ps1xml Format file, which tells PowerShell how to textually render the .NET objects returned by the Cmdlets. A psd1 Module Manifest file, which tells PowerShell what files comprise the Module and a binary DLL which in this case does NOT contain the Cmdlets, but instead is what’s called an “Interop Assembly.”  (sometimes known as Primary Interop Assemblies or PIAs, read about them here: Primary Interop Assemblies – there are subtle differences between IAs and PIAs, but not enough to warrant discussion here). Essentially this DLL lets .NET, and by extension, PowerShell, talk to the native COM APIs that wrap the BITS services on XP,Vista,Win7,Win 2003 and Win 2008. Lets take a peek into the Module Manifest:

  1. @{  
  2. GUID="{8FA5064B-8479-4c5c-86EA-0D311FE48875}" 
  3. Author="Microsoft Corporation" 
  4. CompanyName="Microsoft Corporation" 
  5. Copyright="c Microsoft Corporation. All rights reserved." 
  6. ModuleVersion="1.0.0.0" 
  7. Description="Powershell File Transfer Module" 
  8. PowerShellVersion="2.0" 
  9. CLRVersion="2.0" 
  10. NestedModules="Microsoft.BackgroundIntelligentTransfer.Management" 
  11. FormatsToProcess="FileTransfer.Format.ps1xml" 
  12. RequiredAssemblies=Join-Path $psScriptRoot "Microsoft.BackgroundIntelligentTransfer.Management.Interop.dll" 

If it looks like I just dumped a Hashtable out, you’re right. That’s all a manifest is: a Hashtable. Of course, the key names are important and in this case, lets take a look at two in particular, NestedModules and RequiredAssemblies.

The RequiredAssemblies key is responsible for actively loading .NET assemblies containing standard .NET types. It does not extract Providers and Cmdlets and add them to the runspace; this is what the other key, NestedModules, does. Like I said already, this DLL is the interop assembly. So where is the NestedModules loading that other module from? I don’t see any other DLLs in the directory, and I know there are no Cmdlets in that interop assembly. Lets take a peek at one of the Cmdlets itself and find out:

image

Aha, it’s reading it from the GAC. When PowerShell was installed, it must have installed this DLL there. This is the DLL that contains our Cmdlets. I know this is true because I used one of the Cmdlets to tell me where it lives. “GCM” is the alias for Get-Command which will get us metadata about any given command in PowerShell (including functions – new to v2).

So, lets use a one-liner to get the names of all the Cmdlets in this module, and the synopsis summary for the help:

  1. gcm -module filetransfer | % { $_ | select name, @{Name="Help";Expression={& $_ -? | select -expand synopsis }}} | convertto-html –fragment 

This yields the following:

Name Help
Add-FileTransfer Adds one or more files to an existing Background Intelligent Transfer Service (BITS) t ransfer job.
Clear-FileTransfer Cancels a Background Intelligent Transfer Service (BITS) transfer job.
Complete-FileTransfer Completes a Background Intelligent Transfer Service (BITS) transfer job.
Get-FileTransfer Retrieves the associated BitsJob object for an existing Background Intelligent Transfe r Service (BITS) transfer job.
New-FileTransfer Creates a new Background Intelligent Transfer Service (BITS) transfer job.
Resume-FileTransfer Resumes a Background Intelligent Transfer Service (BITS) transfer job.
Set-FileTransfer Modifies the properties of an existing Business Intelligent Transfer Service (BITS) tr ansfer job.
Suspend-FileTransfer Suspends a Background Intelligent Transfer Service (BITS) transfer job.

I guess this covers it for the moment. Going into a full discussion about how BITS actually works is worth another post in itself. Suffice it to say, there are plenty of examples in the help itself. Just run:

get-help add-filetransfer –example | more

To see an example on how to use the Cmdlet (or any of the others). The team have done a good job here.

Have fun!

posted on Tuesday, February 10, 2009 1:38:27 PM (Eastern Standard Time, UTC-05:00)  #    Comments [1] Trackback
# Tuesday, February 03, 2009

It’s been quite a few years -- November 14, 2006 to be exact -- since the final release of PowerShell 1.0. Let’s see what the lazy buggers have been up to since then. Only kidding, they’re far from lazy; we’ve gained an extra one hundred and six new cmdlets, moving from 131 to 237. We’ve also gained another provider, WSManProvider which lets you explore and manipulate the WS-Man configuration. Finally, the number of public Types (.NET classes usable by 3rd parties to extend PowerShell) has increased from 447 to 749. So how do I know all this? Well, some months ago I wrote a suite of build analysis Cmdlets for examining the assemblies that comprise PowerShell. In its current form it’s of very little use to 3rd parties, but I’ve had some requests to open it up and allow it to analyze any binary modules and snap-ins, which is a good idea I think. Watch this space. Anyway, I’m going to dump out some interest information on the differences between v1.0 and v2.0 CTP3, along with the one-liners I’m using to generate the information.

update feb 5: added breaking changes

Breaking Changes to Windows PowerShell 1.0

The following changes in Windows PowerShell V2.0 CTP3 might prevent features designed for Windows PowerShell 1.0 from working correctly.

    • The value of the PowerShellVersion registry entry in HKLM\SOFTWARE\Microsoft\PowerShell\1\PowerShellEngine has been changed to 2.0.
    • New cmdlets and variables have been added. These are listed below. These new elements might conflict with variables and functions in profiles and scripts.
    • -IEQ operator does a case insensitive comparison on characters.
    • Get-Command gets functions along with cmdlets by default.
    • Any native command that generates a user interface blocks if it is pipelined to the Out-Host cmdlet.
    • Added new language keywords: Begin, Process, and End. Any commands called begin, process or end are interpreted as language keywords and might result in parsing errors.
    • Cmdlet name resolution has changed. In Windows PowerShell 1.0, a runtime error was generated when two Windows PowerShell snap-ins exported cmdlets with the same name. In Windows PowerShell V2, the last cmdlet loaded is the one that is executed if the cmdlet name is not qualified by a snap-in name.
    • Terminating errors that are thrown in a pipeline do not terminate the pipeline. Instead, they are written to the host.
    • A function called with '-?' parameter gets the help topic for the function, if one is included in the function.

There are no changes to Cmdlets other than Get-Command’s –PSSnapin parameter is now an alias to a –Module parameter. This reflects the move away from administrator-installed snap-ins, and towards the friendlier Module system. For all intents and purposes, you can treat v1 snapins as modules as load them as such with the Import-Module Cmdlet.

New Cmdlets

Here are the new Cmdlets, sorted by noun and alongside the textual synopsis is one is present in the CTP3 help, or the syntax if there is no help. The command I ran to generate this was:

  1. compare-psbuildinfo (import-psbuildinfo .\rtm-6-0-6000-16386.psbuild) (import-psbuildinfo .\win7beta1-6-1-7000-0.psbuild) | ? {$_.diff -eq "Added"} | sort noun | % { $_ | add-member -name Synopsis -member noteproperty -value (& $_.name -?|select -expand synopsis) -passthru } | select name,synopsis | convertto-html -fragment > new-cmdlets.htm 

Name Synopsis
Invoke-Command Runs commands on local and remote computers.
Add-Computer Adds computers to a domain or workgroup.
Remove-Computer Removes computers from workgroups or domains.
Rename-Computer Renames a computer.
Restore-Computer Starts a system restore on the local computer.
Checkpoint-Computer Creates a system restore point on the local computer.
Restart-Computer Restarts ("reboots") the operating system on local and remote computers.
Stop-Computer Stops (shuts down) local and remote computers.
Reset-ComputerMachinePassword Resets the machine account password for the computer.
Disable-ComputerRestore Disables the System Restore feature on the specified file system drive.
Enable-ComputerRestore Enables the System Restore feature on the specified file system drive.
Get-ComputerRestorePoint Gets the restore points on the local computer.
Test-ComputerSecureChannel Test-ComputerSecureChannel [-Repair] [-Server <String>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] [-WhatIf] [-Confirm]
Test-Connection Sends ICMP echo request packets ("pings") to one or more computers.
Export-Counter The Export-Counter cmdlet takes PerformanceCounterSampleSet objects and exports them as counter log files.
Import-Counter Imports performance counter log files (.blg, .csv, .tsv) and creates the objects that represent each counter sample in the log.
Get-Counter Gets performance counter data from local and remote computers.
ConvertFrom-Csv Converts object properties in CSV format into CSV versions of the original objects.
ConvertTo-Csv Converts .NET objects into a series of comma-separated, variable-length (CSV) strings.
Register-EngineEvent Register-EngineEvent [-SourceIdentifier] <String> [[-Action] <ScriptBlock>] [-MessageData <PSObject>] [-SupportEvent] [-Forward] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Unregister-Event Unregister-Event [-SourceIdentifier] <String> [-Force] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] [-WhatIf] [-Confirm] Unregister-Event [-SubscriptionId] <Int32> [-Force] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] [-WhatIf] [-Confirm]
New-Event New-Event [-SourceIdentifier] <String> [[-Sender] <PSObject>] [[-EventArguments] <PSObject[]>] [[-MessageData] <PSObject>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Remove-Event Remove-Event [-SourceIdentifier] <String> [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] [-WhatIf] [-Confirm] Remove-Event [-EventIdentifier] <Int32> [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] [-WhatIf] [-Confirm]
Wait-Event Wait-Event [[-SourceIdentifier] <String>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Get-Event Get-Event [[-SourceIdentifier] <String>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Show-EventLog Displays the event logs of the local or a remote computer in Event Viewer.
New-EventLog Creates a new event log and a new event source on a local or remote computer.
Remove-EventLog Deletes an event log or unregisters an event source.
Clear-EventLog Deletes all entries from specified event logs on the local or remote computers.
Write-EventLog Writes an event to an event log.
Limit-EventLog Sets the event log properties that limit the size of the event log and the age of its entries.
Get-EventSubscriber Get-EventSubscriber [[-SourceIdentifier] <String>] [-Force] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Export-FormatData Export-FormatData [-InputObject <ExtendedTypeDefinition[]>] [-FilePath <String>] [-Force] [-NoClobber] [-IncludeScriptBlock] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Get-FormatData Get-FormatData [[-TypeName] <String[]>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Out-GridView Sends output to an interactive table in a separate window.
Clear-History Deletes entries from the command history.
Get-HotFix Gets the QFE updates that have been applied to the local and remote computers.
Stop-Job Stops a Windows PowerShell background job.
Wait-Job Suppresses the command prompt until one or all of the Windows PowerShell background jobs running in the session are complete.
Remove-Job Deletes a Windows PowerShell background job.
Start-Job Starts a Windows PowerShell background job.
Get-Job Gets Windows PowerShell background jobs that are running in the current session.
Receive-Job Gets the results of the Windows PowerShell background jobs in the current session. You can use this cmdlet to retrieve the output and errors of background jobs.
Update-List Adds and removes items from a property value that contains a collection of objects.
Import-LocalizedData Imports language-specific data into scripts and functions based on the UI culture that is selected for the operating system.
Send-MailMessage Sends an e-mail message.
Get-Module Get-Module [[-Name] <String[]>] [-All] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] Get-Module [[-Name] <String[]>] [-ListAvailable] [-Recurse] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Remove-Module Remove-Module [-Name] <String[]> [-Force] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] [-WhatIf] [-Confirm] Remove-Module [-ModuleInfo] <PSModuleInfo[]> [-Force] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] [-WhatIf] [-Confirm]
New-Module New-Module [-ScriptBlock] <ScriptBlock> [-Function <String[]>] [-Cmdlet <String[]>] [-ReturnResult] [-AsCustomObject] [-ArgumentList <Object[]>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] New-Module [-Name] <String> [-ScriptBlock] <ScriptBlock> [-Function <String[]>] [-Cmdlet <String[]>] [-ReturnResult] [-AsCustomObject] [-ArgumentList <Object[]>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Import-Module Import-Module [-Name] <String[]> [-Prefix <String>] [-Function <String[]>] [-Cmdlet <String[]>] [-Variable <String[]>] [-Alias <String[]>] [-Force] [-PassThru] [-AsCustomObject] [-Version <Version>] [-ArgumentList <Object[]>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] Import-Module [-Assembly] <Assembly[]> [-Prefix <String>] [-Function <String[]>] [-Cmdlet <String[]>] [-Variable <String[]>] [-Alias <String[]>] [-Force] [-PassThru] [-AsCustomObject] [-Version <Version>] [-ArgumentList <Object[]>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] Import-Module [-ModuleInfo] <PSModuleInfo[]> [-Prefix <String>] [-Function <String[]>] [-Cmdlet <String[]>] [-Variable <String[]>] [-Alias <String[]>] [-Force] [-PassThru] [-AsCustomObject] [-Version <Version>] [-ArgumentList <Object[]>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Test-ModuleManifest Test-ModuleManifest [-Path] <String> [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
New-ModuleManifest New-ModuleManifest [-Path] <String> -NestedModules <String[]> [-Guid <Guid>] -Author <String> -CompanyName <String> -Copyright <String> [-ModuleToProcess <String>] [-ModuleVersion <Version>] -Description <String> [-PowerShellVersion <Version>] [-ClrVersion <Version>] [-RequiredModules <IDictionary[]>] -TypesToProcess <String[]> -FormatsToProcess <String[]> [-ScriptsToProcess <String[]>] -RequiredAssemblies <String[]> -OtherFiles <String[]> [-ExportedFunctions <String[]>] [-ExportedAliases <String[]>] [-ExportedVariables <String[]>] [-ExportedCmdlets <String[]>] [-PrivateData <Object>] [-PassThru] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] [-WhatIf] [-Confirm]
Export-ModuleMember Export-ModuleMember [[-Function] <String[]>] [-Cmdlet <String[]>] [-Variable <String[]>] [-Alias <String[]>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Register-ObjectEvent Register-ObjectEvent [-InputObject] <PSObject> [-EventName] <String> [[-SourceIdentifier] <String>] [[-Action] <ScriptBlock>] [-MessageData <PSObject>] [-SupportEvent] [-Forward] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Start-Process Starts one or more processes on the local computer.
Debug-Process Debugs one or more processes running on the local computer.
Wait-Process Waits for the processes to be stopped before accepting more input.
Enable-PSBreakpoint Enables the breakpoints in the current console.
Disable-PSBreakpoint Disables the breakpoints in the current console.
Remove-PSBreakpoint Deletes breakpoints from the current console.
Set-PSBreakpoint Sets a breakpoint on a line, command, or variable.
Get-PSBreakpoint Gets the breakpoints that are set in the current console.
Get-PSCallStack Displays the current call stack.
Remove-PSSession Closes one or more Windows PowerShell sessions (PSSessions).
Enter-PSSession Starts an interactive session with a remote computer.
Exit-PSSession Ends an interactive session with a remote computer.
Get-PSSession Gets the Windows PowerShell sessions (PSSessions) in the current session.
Export-PSSession Saves commands from another session in a script module file.
Import-PSSession Imports cmdlets, aliases, functions, and other command types from another session on a local or remote computer into the current session.
New-PSSession Creates a persistent connection to a local or remote computer.
Set-PSSessionConfiguration Set-PSSessionConfiguration [-Name] <String> [-ApplicationBase <String>] [-ThreadApartmentState <ApartmentState>] [-ThreadOptions <PSThreadOptions>] [-StartupScript <String>] [-MaximumReceivedDataSizePerCommandMB <Nullable`1>] [-MaximumReceivedObjectSizeMB <Nullable`1>] [-SecurityDescriptorSddl <String>] [-Force] [-NoServiceRestart] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] Set-PSSessionConfiguration [-Name] <String> [-AssemblyName] <String> [-ConfigurationTypeName] <String> [-ApplicationBase <String>] [-ThreadApartmentState <ApartmentState>] [-ThreadOptions <PSThreadOptions>] [-StartupScript <String>] [-MaximumReceivedDataSizePerCommandMB <Nullable`1>] [-MaximumReceivedObjectSizeMB <Nullable`1>] [-SecurityDescriptorSddl <String>] [-Force] [-NoServiceRestart] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Enable-PSSessionConfiguration Enable-PSSessionConfiguration [[-Name] <String[]>] [-Force] [-SecurityDescriptorSddl <String>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Disable-PSSessionConfiguration Disable-PSSessionConfiguration [[-Name] <String[]>] [-Force] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Register-PSSessionConfiguration Register-PSSessionConfiguration [-Name] <String> [-ProcessorArchitecture <String>] [-ApplicationBase <String>] [-ThreadApartmentState <ApartmentState>] [-ThreadOptions <PSThreadOptions>] [-StartupScript <String>] [-MaximumReceivedDataSizePerCommandMB <Nullable`1>] [-MaximumReceivedObjectSizeMB <Nullable`1>] [-SecurityDescriptorSddl <String>] [-Force] [-NoServiceRestart] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] Register-PSSessionConfiguration [-Name] <String> [-AssemblyName] <String> [-ConfigurationTypeName] <String> [-ProcessorArchitecture <String>] [-ApplicationBase <String>] [-ThreadApartmentState <ApartmentState>] [-ThreadOptions <PSThreadOptions>] [-StartupScript <String>] [-MaximumReceivedDataSizePerCommandMB <Nullable`1>] [-MaximumReceivedObjectSizeMB <Nullable`1>] [-SecurityDescriptorSddl <String>] [-Force] [-NoServiceRestart] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Unregister-PSSessionConfiguration Unregister-PSSessionConfiguration [-Name] <String> [-Force] [-NoServiceRestart] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Get-PSSessionConfiguration Get-PSSessionConfiguration [[-Name] <String[]>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Get-Random Gets a random number or selects objects randomly from a collection.
Set-StrictMode Establishes and enforces coding rules in expressions, scripts, and script blocks.
ConvertFrom-StringData Converts a string containing one or more "name=value" pairs to a hash table.
Undo-Transaction Rolls back the active transaction.
Use-Transaction Adds the script block to the active transaction.
Complete-Transaction Commits the active transaction.
Get-Transaction Gets the current (active) transaction.
Start-Transaction Starts a transaction.
Add-Type Adds a .NET type (a class) to a Windows PowerShell session.
New-WebServiceProxy Creates a Web service proxy object that lets you use and manage the Web service in Windows PowerShell.
Get-WinEvent Gets events from event logs and event tracing log files on local and remote computers. This cmdlet runs only on Windows Vista and later versions of Windows.
Register-WmiEvent Register-WmiEvent [-Class] <String> [[-SourceIdentifier] <String>] [[-Action] <ScriptBlock>] [-Namespace <String>] [-Credential <PSCredential>] [-ComputerName <String>] [-Timeout <Int64>] [-MessageData <PSObject>] [-SupportEvent] [-Forward] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] Register-WmiEvent [-Query] <String> [[-SourceIdentifier] <String>] [[-Action] <ScriptBlock>] [-Namespace <String>] [-Credential <PSCredential>] [-ComputerName <String>] [-Timeout <Int64>] [-MessageData <PSObject>] [-SupportEvent] [-Forward] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Set-WmiInstance Creates or modifies instances of WMI classes.
Invoke-WmiMethod Calls WMI methods.
Remove-WmiObject Deletes WMI classes and instances.
Disconnect-WSMan Disconnect-WSMan [[-ComputerName] <String>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Connect-WSMan Connect-WSMan [[-ComputerName] <String>] [-ApplicationName <String>] [-Authentication <AuthenticationMechanism>] [-Credential <PSCredential>] [-OptionSet <Hashtable>] [-Port <Int32>] [-SessionOption <SessionOption>] [-UseSSL] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] Connect-WSMan [-Authentication <AuthenticationMechanism>] [-ConnectionURI <Uri>] [-Credential <PSCredential>] [-OptionSet <Hashtable>] [-Port <Int32>] [-SessionOption <SessionOption>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Test-WSMan Test-WSMan [[-ComputerName] <String>] [-Authentication <AuthenticationMechanism>] [-Credential <PSCredential>] [-Port <Int32>] [-UseSSL] [-ApplicationName <String>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Invoke-WSManAction Invoke-WSManAction [-ResourceURI] <Uri> [-Action] <String> [[-SelectorSet] <Hashtable>] [-Authentication <AuthenticationMechanism>] [-ConnectionURI <Uri>] [-Credential <PSCredential>] [-FilePath <String>] [-OptionSet <Hashtable>] [-SessionOption <SessionOption>] [-ValueSet <Hashtable>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] Invoke-WSManAction [-ResourceURI] <Uri> [-Action] <String> [[-SelectorSet] <Hashtable>] [-ApplicationName <String>] [-Authentication <AuthenticationMechanism>] [-ComputerName <String>] [-Credential <PSCredential>] [-FilePath <String>] [-OptionSet <Hashtable>] [-Port <Int32>] [-SessionOption <SessionOption>] [-UseSSL] [-ValueSet <Hashtable>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Get-WSManCredSSP Get-WSManCredSSP [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Enable-WSManCredSSP Enable-WSManCredSSP [-DelegateComputer] <String[]> [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Disable-WSManCredSSP Disable-WSManCredSSP [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Remove-WSManInstance Remove-WSManInstance [-ResourceURI] <Uri> [-SelectorSet] <Hashtable> [-ApplicationName <String>] [-Authentication <AuthenticationMechanism>] [-ComputerName <String>] [-Credential <PSCredential>] [-OptionSet <Hashtable>] [-Port <Int32>] [-SessionOption <SessionOption>] [-UseSSL] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] Remove-WSManInstance [-ResourceURI] <Uri> [-SelectorSet] <Hashtable> [-Authentication <AuthenticationMechanism>] [-ConnectionURI <Uri>] [-Credential <PSCredential>] [-OptionSet <Hashtable>] [-SessionOption <SessionOption>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
New-WSManInstance New-WSManInstance [-ResourceURI] <Uri> [-SelectorSet] <Hashtable> [-ApplicationName <String>] [-Authentication <AuthenticationMechanism>] [-ComputerName <String>] [-Credential <PSCredential>] [-FilePath <String>] [-OptionSet <Hashtable>] [-Port <Int32>] [-SessionOption <SessionOption>] [-UseSSL] [-ValueSet <Hashtable>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] New-WSManInstance [-ResourceURI] <Uri> [-SelectorSet] <Hashtable> [-Authentication <AuthenticationMechanism>] [-ConnectionURI <Uri>] [-Credential <PSCredential>] [-FilePath <String>] [-OptionSet <Hashtable>] [-SessionOption <SessionOption>] [-ValueSet <Hashtable>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Get-WSManInstance Get-WSManInstance [-ResourceURI] <Uri> [-ApplicationName <String>] [-Authentication <AuthenticationMechanism>] [-ComputerName <String>] [-ConnectionURI <Uri>] [-Credential <PSCredential>] [-Dialect <Uri>] [-Fragment <String>] [-OptionSet <Hashtable>] [-Port <Int32>] [-SelectorSet <Hashtable>] [-SessionOption <SessionOption>] [-UseSSL] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] Get-WSManInstance [-ResourceURI] <Uri> [-ApplicationName <String>] [-Authentication <AuthenticationMechanism>] [-BasePropertiesOnly] [-ComputerName <String>] [-ConnectionURI <Uri>] [-Credential <PSCredential>] [-Dialect <Uri>] -Enumerate [-Filter <String>] [-OptionSet <Hashtable>] [-Port <Int32>] [-References] [-ReturnType <String>] [-SessionOption <SessionOption>] [-Shallow] [-UseSSL] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Set-WSManInstance Set-WSManInstance [-ResourceURI] <Uri> [[-SelectorSet] <Hashtable>] [-ApplicationName <String>] [-Authentication <AuthenticationMechanism>] [-ComputerName <String>] [-Credential <PSCredential>] [-Dialect <Uri>] [-FilePath <String>] [-Fragment <String>] [-OptionSet <Hashtable>] [-Port <Int32>] [-SessionOption <SessionOption>] [-UseSSL] [-ValueSet <Hashtable>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] Set-WSManInstance [-ResourceURI] <Uri> [[-SelectorSet] <Hashtable>] [-Authentication <AuthenticationMechanism>] [-ConnectionURI <Uri>] [-Credential <PSCredential>] [-Dialect <Uri>] [-FilePath <String>] [-Fragment <String>] [-OptionSet <Hashtable>] [-SessionOption <SessionOption>] [-ValueSet <Hashtable>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Set-WSManQuickConfig Set-WSManQuickConfig [-UseSSL] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
New-WSManSessionOption New-WSManSessionOption [-ProxyAccessType <ProxyAccessType>] [-ProxyAuthentication <ProxyAuthentication>] [-ProxyCredential <PSCredential>] [-SkipCACheck] [-SkipCNCheck] [-SkipRevocationCheck] [-SPNPort <Int32>] [-OperationTimeout <Int32>] [-NoEncryption] [-UseUTF16] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
Select-Xml Select-Xml [-XPath] <String> [-Path] <String[]> [-Namespace <Hashtable>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] Select-Xml [-XPath] <String> [-Xml] <XmlNode[]> [-Namespace <Hashtable>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>] Select-Xml [-XPath] <String> [-Content] <String[]> [-Namespace <Hashtable>] [-Verbose] [-Debug] [-ErrorAction <ActionPreference>] [-WarningAction <ActionPreference>] [-ErrorVariable <String>] [-WarningVariable <String>] [-OutVariable <String>] [-OutBuffer <Int32>]
ConvertTo-Xml Creates an XML-based representation of an object.

Whew, that’s quite a few. Now, onto the API.

.NET API Differences

This time, I’m just dumping out the namespaces and Types per namespace. It would be a bit much to dump out all the Types themselves. The one-liner:

  1. $v1.api | group namespace | select name, count | convertto-html -fragment > .\v1-types.htm 
v1.0 RTM API

Here are the namspaces and respective public Type count for v1.0:

Name Count
Microsoft.PowerShell.Commands 196
Microsoft.PowerShell 11
Microsoft.PowerShell.Commands.Internal.Format 4
System.Management.Automation 169
System.Management.Automation.Internal 6
System.Management.Automation.Host 15
System.Management.Automation.Runspaces 33
System.Management.Automation.Provider 13

v2.0 CTP3 API

Here are the namspaces and respective public Type count for v2.0 CTP3:

Name Count
Microsoft.PowerShell.Commands 311
Microsoft.PowerShell.Commands.GetCounter 4
Microsoft.PowerShell 14
Microsoft.PowerShell.Commands.Internal.Format 4
Microsoft.WSMan.Management 40
System.Management.Automation 262
System.Management.Automation.Internal 7
System.Management.Automation.Runspaces 61
System.Management.Automation.Host 17
System.Management.Automation.Remoting 10
System.Management.Automation.Provider 14
Microsoft.PowerShell.Commands.Internal 4
Microsoft.PowerShell.Commands.Management 1

As you can see, there has been a nice expansion of namespaces and Types to work with, mostly coming from the sterling work being done to generalize the “Jobs” infrastructure. Also, a fair chunk is tied up with the refactoring and reorganizing of Runspaces to allow for jobs (which also covers eventing), remoting and background pipelines. This is something I will cover in more detail in a future post.

Have fun!

posted on Tuesday, February 03, 2009 7:18:14 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] Trackback
# Tuesday, December 23, 2008

Just to be completely silly, I thought I’d do a series of posts on CTP3 features themed around Christmas. Hmm. That might read better as a series of Christmas posts themed around CTP3. A very original idea I’m sure, but hey, those who know me will know that I never pass up the opportunity to make a bad joke. So, without further adieu:

On the first day of Christmas, Jeffrey gave to me:

Nested Here-Strings

Here-Strings can now be embedded within each other to make it even easier to construct literal documents! Delimit any nested code between $( and ) and then continue to use a nested string within that as if it was completely stand alone. It just works! Cool, eh?

  1. function Get-CommandDefinitionHtml {  
  2.       
  3.     # this tells powershell to allow advanced features,  
  4.     # like the [validatenotnullorempty()] attribute below.  
  5.     [CmdletBinding()]  
  6.     param(  
  7.         [ValidateNotNullOrEmpty()]  
  8.         [string]$name 
  9.     )  
  10.  
  11.     $command = get-command $name 
  12.       
  13.     # Look mom! I'm a cmdlet!  
  14.     $PSCmdlet.WriteVerbose("Dumping HTML for " + $command)  
  15.       
  16. @"  
  17.     <html>  
  18.         <head>  
  19.             <title>$($command.name)</title>  
  20.         </head>  
  21.         <body>  
  22.             <table border="1">  
  23. $(  
  24.     $command.parametersets | % {  
  25. @" 
  26.  
  27.             <tr>  
  28.                 <td>$($_.name)</td>  
  29.                 <td>  
  30.                     <table border="1">  
  31.                         <tr>  
  32.                             <th colspan="8">Parameters</th>  
  33.                               
  34. $(  
  35.         $count = 0  
  36.         $_.parameters | % {  
  37.             if (0 -eq ($count % 8)) {  
  38. @"  
  39.                         </tr>  
  40.                         <tr>  
  41. "@  
  42.             }                  
  43. @"  
  44.                             <td>$($_.name)</td>  
  45. "@              
  46.             $count++  
  47.     }  
  48. )  
  49.                         </tr>                          
  50.                     </table>  
  51.                 </td>  
  52.             </tr>  
  53. "@  
  54.     }  
  55. )  
  56.             </table>          
  57.         </body>  
  58.     </html>  
  59. "@      
  60. }  
  61.  
  62. Get-CommandDefinitionHtml get-item > out.html  
  63.  
  64. # show in browser  
  65. invoke-item out.html 
posted on Tuesday, December 23, 2008 4:16:03 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] Trackback
# Sunday, December 21, 2008

This time around, I thought I’d show how to work with programmatically generated dynamic parameters, as opposed to the statically defined sets we saw the last time. The context here is a fairly silly Cmdlet, but it’s good enough to demonstrate the concept end to end. It’s a Cmdlet for removing a file. It takes one string parameter which is the path to the file. The dynamic parameter I’m going to add is a –Force parameter. The trick is, this parameter will only be added if the current user is an administrator (XP), or is elevated as one (Vista).

This first portion of the Cmdlet defines the usual stuff like a verb and noun. This time though, I’m using a regular class constructor. It’s not often you see constructors in simple Cmdlets because typically all one would usually do is override one or more of the three processing methods BeginProcessing, ProcessRecord and EndProcessing. In this case, I need to create a instance of a “RuntimeDefinedParameterDictionary,” which does exactly what it says on the tin. It’s a dictionary of parameters, the key being a string (the name of the parameter) and the value being a instance of a RuntimeDefinedParameter class. These classes are all members of the System.Management.Automation namespace.

In the constructor, I’m calling a generic method defined as AddDynamicParameter<T>(string name). This is only called if the current user is an admin. I’ve defined three generic helper methods which you can see a little further down below.

  1. [Cmdlet(VerbsCommon.Remove, NOUN_FILE)]  
  2. public class RemoveFileCommand : PSCmdlet, IDynamicParameters  
  3. {  
  4.     private const string NOUN_FILE      = "File";  
  5.     private const string SWITCH_FORCE   = "Force";  
  6.  
  7.     private readonly RuntimeDefinedParameterDictionary _parameters;  
  8.  
  9.     public RemoveFileCommand()  
  10.     {  
  11.         _parameters = new RuntimeDefinedParameterDictionary();  
  12.  
  13.         // we only want to add the -Force parameter if  
  14.         // the current user is an administrator  
  15.         var principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());  
  16.  
  17.         // if vista and not elevated, this will be false even  
  18.         // if you are a member of administrators.  
  19.         if (principal.IsInRole(WindowsBuiltInRole.Administrator))  
  20.         {  
  21.             this.AddDynamicParameter<SwitchParameter>(SWITCH_FORCE);  
  22.         }  
  23.     }  
  24.  
  25.     [Parameter]  
  26.     public string FilePath  
  27.     {  
  28.         get;  
  29.         set;  
  30.     }   
  31.  
  32.     protected override void EndProcessing()  
  33.     {  
  34.         // does file exist?  
  35.         if (File.Exists(FilePath))  
  36.         {  
  37.             RemoveFile();  
  38.         }  
  39.         else 
  40.         {  
  41.             WriteWarning(FilePath + " does not exist.");  
  42.         }  
  43.     } 

This is a simple piece of code who’s role is to remove the file specified by the user. I’ve omitted the actual code that would delete the file for brevity. I’m using another helper method to see if the –Force parameter has been added to the Cmdlet’s definition, and if so, was it specified by the invoker of the Cmdlet. The idea is here is that the Cmdlet will not remove the file if it’s marked Read-Only, but if –Force is specified it will remove the R/O attribute and continue as planned.

  1. private void RemoveFile()  
  2. {  
  3.     // read file attributes  
  4.     var attribs = File.GetAttributes(FilePath);  
  5.  
  6.     // is read-only attribute set?  
  7.     if ((attribs & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)  
  8.     {  
  9.         bool shouldForce;  
  10.  
  11.         // see if the dynamic switch -Force was added (and specified)  
  12.         if (TryGetSwitchParameter(SWITCH_FORCE, out shouldForce))  
  13.         {  
  14.             WriteVerbose("Force.IsPresent: " + shouldForce);  
  15.         }  
  16.  
  17.         if (shouldForce)  
  18.         {  
  19.             RemoveReadOnlyAttribute();  
  20.         }  
  21.         else 
  22.         {  
  23.             WriteWarning(FilePath + " is marked Read-Only!");  
  24.             return;  
  25.         }  
  26.     }  
  27.  
  28.     // ... code to remove file ...  

And the final piece is here. The first method GetDynamicParameters, belongs to the IDynamicParameters interface and tells PowerShell that the Cmdlet may return extra parameters not defined on the class itself. In this case, we are returning a RuntimeDefinedParameterDictionary instead of a statically defined parameters on a nested class.

  1. public object GetDynamicParameters()  
  2. {  
  3.     return _parameters;  
  4. }  
  5.  
  6. // add a simple parameter of type T to this cmdlet  
  7. private void AddDynamicParameter<T>(string name)  
  8. {  
  9.     // create a parameter of type T.  
  10.     var parameter = new RuntimeDefinedParameter  
  11.                     {  
  12.                         Name = name,  
  13.                         ParameterType = typeof (T),                                  
  14.                     };  
  15.  
  16.     // add the [parameter] attribute  
  17.     var attrib = new ParameterAttribute  
  18.                  {                               
  19.                      ParameterSetName =  
  20.                         ParameterAttribute.AllParameterSets  
  21.                  };  
  22.       
  23.     parameter.Attributes.Add(attrib);  
  24.  
  25.     _parameters.Add(name, parameter);  
  26. }  
  27.  
  28. private bool TryGetSwitchParameter(string name, out bool isPresent)  
  29. {  
  30.     RuntimeDefinedParameter parameter;  
  31.       
  32.     if (TryGetDynamicParameter(name, out parameter))  
  33.     {  
  34.         isPresent = parameter.IsSet;  
  35.         return true;  
  36.     }  
  37.  
  38.     isPresent = false;  
  39.     return false;  
  40. }  
  41.  
  42. // get a parameter of type T.  
  43. private bool TryGetParameter<T>(string name, out T value)  
  44. {  
  45.     RuntimeDefinedParameter parameter;  
  46.       
  47.     if (TryGetDynamicParameter(name, out parameter))  
  48.     {  
  49.         value = (T)parameter.Value;  
  50.         return true;  
  51.     }  
  52.  
  53.     value = default(T);  
  54.       
  55.     return false;  
  56. }  
  57.  
  58. // try to get a dynamically added parameter  
  59. private bool TryGetDynamicParameter(string name, out RuntimeDefinedParameter value)  
  60. {  
  61.     if (_parameters.ContainsKey(name))  
  62.     {  
  63.         value = _parameters[name];  
  64.         return true;  
  65.     }  
  66.  
  67.     // need to set this before leaving the method  
  68.     value = null;  
  69.  
  70.     return false;  
  71. }  

Finally, the three helper methods are revealed. One is used for checking for dynamic SwitchParameters, the next is for ordinary parameters that return type T, the generic argument. The third method, TryGetDynamicParameter is used by the first two methods.

I hope this helps reveal some of the mystery behind dynamic parameters on Cmdlets. There is one more type of dynamic parameter that I will be examining in one of my next few posts, that is the scenario where a provider (like the FileSystemProvider or RegistryProvider) passes a dynamic parameter to a Cmdlet. In this particular case, the provider can only pass dynamic parameters to the built-in Cmdlets that operate on providers, e.g. Get-ChildItem, Get-Item, Get-ItemProperty etc.

Have fun!

posted on Sunday, December 21, 2008 5:28:27 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] Trackback
# Wednesday, November 19, 2008

It seems lots of people are catching the PowerShell bug these days. People who previously considered themselves as administrators have learned enough of the magic from using PowerShell from day to day over the last few months that they feel comfortable enough to tinker around with C#.

This is an example Cmdlet skeleton that is designed to work with Files and Directories. It looks after resolving wildcards, supports –WhatIf and –Confirm, accepting files and/or directories from the pipeline or accepting strings of paths from the pipeine. It also ensures that the only types of paths it can accept lie on the File System. Here’s an example of the invocation styles it supports:

cmdlet

Here’s the source code for this. It doesn’t really do a lot. It spits out two different types of custom objects: one for a file, and another for a directory. Feel free to do what you like with it; it’s yours. Have fun.

using System;
using System.Collections.Generic;
using System.IO;
using System.Management.Automation;
using Microsoft.PowerShell.Commands;
namespace PSQuickStart
{
    [Cmdlet(VerbsCommon.Get, Noun,
        DefaultParameterSetName = ParmamSetPath,
        SupportsShouldProcess = true)
    ]
    public class GetFileMetadataCommand : PSCmdlet
    {
        private const string Noun = "FileMetadata";
        private const string ParamSetLiteral = "Literal";
        private const string ParmamSetPath = "Path";
        private string[] _paths;
        private bool _shouldExpandWildcards;
        [Parameter(
            Position = 0,
            Mandatory = true,
            ValueFromPipeline = false,
            ValueFromPipelineByPropertyName = true,
            ParameterSetName = ParamSetLiteral)
        ]
        [Alias("PSPath")]
        [ValidateNotNullOrEmpty]
        public string[] LiteralPath
        {
            get { return _paths; }
            set { _paths = value; }
        }
        [Parameter(
            Position = 0,
            Mandatory = true,
            ValueFromPipeline = true,
            ValueFromPipelineByPropertyName = true,
            ParameterSetName = ParmamSetPath)
        ]
        [ValidateNotNullOrEmpty]
        public string[] Path
        {
            get { return _paths; }
            set
            {
                _shouldExpandWildcards = true;
                _paths = value;
            }
        }
        protected override void ProcessRecord()
        {
            foreach (string path in _paths)
            {
                // This will hold information about the provider containing
                // the items that this path string might resolve to.                
                ProviderInfo provider;
                // This will be used by the method that processes literal paths
                PSDriveInfo drive;
                // this contains the paths to process for this iteration of the
                // loop to resolve and optionally expand wildcards.
                List<string> filePaths = new List<string>();
                if (_shouldExpandWildcards)
                {
                    // Turn *.txt into foo.txt,foo2.txt etc.
                    // if path is just "foo.txt," it will return unchanged.
                    filePaths.AddRange(this.GetResolvedProviderPathFromPSPath(path, out provider));
                }
                else
                {
                    // no wildcards, so don't try to expand any * or ? symbols.                    
                    filePaths.Add(this.SessionState.Path.GetUnresolvedProviderPathFromPSPath(
                        path, out provider, out drive));
                }
                // ensure that this path (or set of paths after wildcard expansion)
                // is on the filesystem. A wildcard can never expand to span multiple
                // providers.
                if (IsFileSystemPath(provider, path) == false)
                {
                    // no, so skip to next path in _paths.
                    continue;
                }
                // at this point, we have a list of paths on the filesystem.
                foreach (string filePath in filePaths)
                {
                    PSObject custom;
                    // If -whatif was supplied, do not perform the actions
                    // inside this "if" statement; only show the message.
                    //
                    // This block also supports the -confirm switch, where
                    // you will be asked if you want to perform the action
                    // "get metadata" on target: foo.txt
                    if (ShouldProcess(filePath, "Get Metadata"))
                    {
                        if (Directory.Exists(filePath))
                        {
                            custom = GetDirectoryCustomObject(new DirectoryInfo(filePath));
                        }
                        else
                        {
                            custom = GetFileCustomObject(new FileInfo(filePath));
                        }
                        WriteObject(custom);
                    }
                }
            }
        }
        private PSObject GetFileCustomObject(FileInfo file)
        {
            // this message will be shown if the -verbose switch is given
            WriteVerbose("GetFileCustomObject " + file);
            // create a custom object with a few properties
            PSObject custom = new PSObject();
            custom.Properties.Add(new PSNoteProperty("Size", file.Length));
            custom.Properties.Add(new PSNoteProperty("Name", file.Name));
            custom.Properties.Add(new PSNoteProperty("Extension", file.Extension));
            return custom;
        }
        private PSObject GetDirectoryCustomObject(DirectoryInfo dir)
        {
            // this message will be shown if the -verbose switch is given
            WriteVerbose("GetDirectoryCustomObject " + dir);
            // create a custom object with a few properties
            PSObject custom = new PSObject();
            int files = dir.GetFiles().Length;
            int subdirs = dir.GetDirectories().Length;
            custom.Properties.Add(new PSNoteProperty("Files", files));
            custom.Properties.Add(new PSNoteProperty("Subdirectories", subdirs));
            custom.Properties.Add(new PSNoteProperty("Name", dir.Name));
            return custom;
        }
        private bool IsFileSystemPath(ProviderInfo provider, string path)
        {
            bool isFileSystem = true;
            // check that this provider is the filesystem
            if (provider.ImplementingType != typeof(FileSystemProvider))
            {
                // create a .NET exception wrapping our error text
                ArgumentException ex = new ArgumentException(path +
                    " does not resolve to a path on the FileSystem provider.");
                // wrap this in a powershell errorrecord
                ErrorRecord error = new ErrorRecord(ex, "InvalidProvider",
                    ErrorCategory.InvalidArgument, path);
                // write a non-terminating error to pipeline
                this.WriteError(error);
                // tell our caller that the item was not on the filesystem
                isFileSystem = false;
            }
            return isFileSystem;
        }
    }
}
posted on Wednesday, November 19, 2008 5:58:18 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] Trackback
# Thursday, November 13, 2008

Here’s just a quick rundown of the changes in PowerShell 2.0 in comparison to the last public release, CTP2. This may be helpful to those of you who don’t have access to the Windows 7 PDC bits. Remember, things are still subject to change - it’s not in beta yet.

Unchanged cmdlets are not listed here.

Added (or renamed*) Cmdlets

Enter-PSSession
Remove-PSSession
Get-PSSession
Exit-PSSession
Get-PSSessionConfiguration
Unregister-PSSessionConfiguration
Register-PSSessionConfiguration
Debug-Process
Test-ModuleManifest
New-ModuleManifest
New-WSManSessionOption
New-PSSession
Import-PSSession
Export-PSSession
Set-PSSessionConfiguration
Get-WSManInstance
Get-WSManCredSSP
Enable-WSManCredSSP
Set-WSManInstance
Set-WSManQuickConfig
New-WSManInstance
Remove-WSManInstance
Ping-WSMan
New-WebServiceProxy
Get-PSTransaction
Connect-WSMan
Disable-WSManCredSSP
Invoke-WSManAction
Disconnect-WSMan
Get-ComputerRestorePoint
Disable-ComputerRestore
Enable-ComputerRestore
Get-Counter
Clear-EventLog
Export-Counter
Import-Counter
Checkpoint-Computer
Restart-Computer
Stop-Computer
Ping-Computer
Resume-BitsTransfer
Set-BitsTransfer
Suspend-BitsTransfer
Add-BitsFile
Clear-BitsTransfer
Remove-EventLog
Restore-Computer
New-Module
Get-HotFix
Complete-BitsTransfer
Write-EventLog
Show-EventLog
Limit-EventLog
Get-BitsTransfer
New-BitsTransfer
New-EventLog

Changed Cmdlets (parameter or parameterset differences)

Invoke-Command
Receive-PSJob
Set-WmiInstance
Stop-PSJob
Wait-PSJob
Remove-PSJob
Export-ModuleMember
Start-PSJob
Get-PSJob
Add-Module
Set-Service

   

Removed (or renamed*) Cmdlets

Pop-Runspace
New-Runspace
Push-Runspace
Get-Runspace
Remove-Runspace

   

* e.g. The *-Runspace Cmdlets have been renamed to *-PSSession

posted on Thursday, November 13, 2008 11:15:00 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] Trackback
# Thursday, October 30, 2008

Fellow PowerShell MVP and developer all-round expert administrator Brandon Shell asked me how he could navigate to a Cmdlet’s implementation in Lutz Roeder’s Reflector -- which has now been acquired by Red-Gate Software btw. At first I was going to explain to him how snap-ins work and how to figure out where things are, and then a really simple trick hit me that uses some fairly secret command-line parameter that Reflector can accept, namely the /select parameter:

  1. function Reflect-Cmdlet {  
  2.     param([Management.Automation.CommandInfo]$command)  
  3.     if ($input) {  
  4.         trap { $_; break }  
  5.         $command = $input | select -first 1  
  6.     }      
  7.          
  8.     # resolve to command if this is an alias  
  9.     while ($command.CommandType -eq "Alias") {  
  10.         $command = Get-Command ($command.definition)  
  11.     }  
  12.       
  13.     $name = $command.ImplementingType      
  14.     $DLL = $command.DLL  
  15.       
  16.     if (-not (gcm reflector.exe -ea silentlycontinue)) {  
  17.         throw "I can't find Reflector.exe in your path." 
  18.     }  
  19.        
  20.     reflector /select:$name $DLL 

Just pipe the output of get-command to it, like: gcm dir | reflect-cmdlet and Reflector will open up with the class selected (it takes a few seconds).

Update: Doug pointed out in a comment that the gcm reflector.exe line could benefit from an erroraction to keep it silent on failure, so only the throw message shows. Thanks Doug!

posted on Thursday, October 30, 2008 1:44:40 PM (Eastern Standard Time, UTC-05:00)  #    Comments [3] Trackback
# Wednesday, October 15, 2008

The verbs list for naming your Cmdlets is pretty strict. You should definitely try to pick one of the known verbs. You can see them here:

function Get-Verb {
    [psobject].assembly.getexportedtypes() | `
        ? {$_.name -like "Verbs*"} | gm -static -membertype property | `
        sort Name | select Name
}

ps> Get-Verb

The noun end of the spectrum is pretty open-ended. Single nouns are better, and try to use the singular if you can. Cmdlets typically return one or more objects. so the singular form is the convention - better than trying to name your Cmdlet "Get-Noun(s)" which is just plain silly.

To prefix or not to prefix: this is a sticky one. The Religious Right, aka the Microsoft Powershell team, dictate that you should not prefix. The reality is more complicated and is under constant debate. If you pick a verb-noun pair that already exists and is currently loaded into powershell, you must disambiguate the command with the snapin name (snapinname\verb-noun) or it won't run. The snapin name is typically long and ugly. A noun prefix is typically short and sweet. The problem with the latter is that your commands are now harder to discover for someone who doesn't know they are there (and as such doesn't know your magic prefix). Ultimately though, people load your snapin explicitly and should know the prefix, so I tend to lean towards this although I feel a strong connection with the "One Noun Way."

(taken from one of my newgroup posts)

posted on Wednesday, October 15, 2008 12:20:19 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] Trackback
# Tuesday, August 12, 2008

It’s getting harder to post useful scripting tips for PowerShell these days as there are so many talented hardcore scripting bloggers around. My day to day is job is not system/network/server administrator; I’m a .NET developer, having started the C# habit about eight or nine years ago with the early CLR 1.0 beta. So, from here on in, I’ve decided that a better direction for me to take from now on is that of a PowerShell developer,  as opposed to a scripter. There are very few (if any?) dedicated PowerShell developer blogs around, and so I figured I should try to fill that gap as best I can. I have a not insignificant amount of experience writing providers, cmdlets and other widgety bits, so it’s a good time to share my experiences. Of course, my way is not “the” way, so please reply with your own experiences/advice/mocking/whatever. ;-)

That said, I am not eschewing scripting altogether – I have some stuff in the pipeline (har-har) concerning areas I’m interested in, like eventing and jobs/remoting.

posted on Tuesday, August 12, 2008 10:03:20 AM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] Trackback