Differences between PowerShell 1.0 RTM and Powershell 2.0 CTP3/Win7 Beta

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!

CTP3: The [RunspaceFactory] and [PowerShell] Accelerators

You might have noticed these two accelerators in the list I published recently along with the technique how to add your own type accelerators. It’s not immediately clear that they are related, but they very much are. This is going to be a fairly developer-oriented post, so there won’t be any hand-holding here.

[PowerShell]

The [PowerShell] accelerator is aliased to System.Management.Automation.PowerShell. It has one static method, Create(), which returns an instance of the class itself. In v1, if you wanted to set up asynchronous pipelines and do other fancy stuff, you had to get your hands dirty with Runspace and Pipeline instances and know how to wire them all together. The [PowerShell] class makes it a lot easier to do this; think of it a “PowerShell Pipeline Runner” class. At its simplest, you can just “new up” an instance, assign some script using the AddScript method and call Invoke(). You can run this asynchronously using the BeginInvoke/EndInvoke pattern which should be familiar to all .NET developers who’ve done a bit of threading work.

  1. # create a new pipeline  
  2. $ps = [powershell]::create()  
  3.  
  4. # add a command (returns Command object)  
  5. [void] $ps.AddScript("ls")  
  6.  
  7. # invoke synchronously, returning results of "ls."  
  8. $results = $ps.Invoke()  
  9.  
  10. # clean up  
  11. $ps.dispose() 

[RunspaceFactory]

This accelerator is aliased to System.Management.Automation.Runspaces.RunspaceFactory. It has two static methods of interest, CreateRunspace and CreateRunspacePool. I’m going to focus on the latter because it has more interesting uses which you will see. This latter method lets you create a collection of Runspace instances that are essentially reusable. The great thing is that you don’t have to worry about any of the details. It just works; this leads me to the next part: queuing local pipeline jobs to be run in the background.

The pool you create can be constrained in many ways by using the various overloads of the CreateRunspacePool. You can even pass it a RunspaceConnectionInfo object so that the queued pipelines are run on remote servers. This is done by using the New-PSSession cmdlet to create a session to a remote machine running PowerShell 2.0 with WinRM configured correctly.

Queueing Pipelines to a Runspace Pool

This is where the magic really happens. Simply new up a PowerShell instance, assign the pool to it and run a command. New up as many PowerShell instnaces as you like, and as long as you assign each of them the same pool, the pool automagically looks after processing them as fast as it can and will never go over its hard limits you give it for the number of simultaneous runspaces. In this next script, I set up a pool of three runspaces. I then queue up six pipelines to be run. I am using the BeginInvoke method to start the command in the background. You’ll see when it runs that each command will make a beep of a certain frequency when it finally starts up. You can hear the first three jobs start up pretty much straight away, as each completes, another starts up. Magic!

  1. #require -version 2.0  
  2.  
  3. # create a pool of 3 runspaces  
  4. $pool = [runspacefactory]::CreateRunspacePool(1, 3)  
  5. $pool.Open()  
  6.  
  7. write-host "Available Runspaces: $($pool.GetAvailableRunspaces())" 
  8.  
  9. $jobs = @()  
  10. $ps = @()  
  11. $wait = @()  
  12.  
  13. # run 6 background pipelines  
  14. for ($i = 0; $i -lt 6; $i++) {  
  15.      
  16.    # create a "powershell pipeline runner"  
  17.    $ps += [powershell]::create()  
  18.      
  19.    # assign our pool of 3 runspaces to use  
  20.    $ps[$i].runspacepool = $pool 
  21.      
  22.    $freq = 440 + ($i * 10)  
  23.    $sleep = (1 * ($i + 1))  
  24.      
  25.    # test command: beep and wait a certain time  
  26.    [void]$ps[$i].AddScript(  
  27.         "[console]::Beep($freq, 30); sleep -seconds $sleep")  
  28.      
  29.    # start job  
  30.    write-host "Job $i will run for $sleep second(s)" 
  31.    $jobs += $ps[$i].BeginInvoke();  
  32.      
  33.    write-host "Available runspaces: $($pool.GetAvailableRunspaces())" 
  34.      
  35.    # store wait handles for WaitForAll call  
  36.    $wait += $jobs[$i].AsyncWaitHandle  
  37. }  
  38.  
  39. # wait 20 seconds for all jobs to complete, else abort  
  40. $success = [System.Threading.WaitHandle]::WaitAll($wait, 20000)  
  41.  
  42. write-host "All completed? $success" 
  43.  
  44. # end async call  
  45. for ($i = 0; $i -lt 6; $i++) {  
  46.  
  47.     write-host "Completing async pipeline job $i" 
  48.  
  49.     try {  
  50.  
  51.         # complete async job  
  52.         $ps[$i].EndInvoke($jobs[$i])  
  53.  
  54.     } catch {  
  55.       
  56.         # oops-ee!  
  57.         write-warning "error: $_" 
  58.     }  
  59.  
  60.     # dump info about completed pipelines  
  61.     $info = $ps[$i].InvocationStateInfo  
  62.  
  63.     write-host "State: $($info.state) ; Reason: $($info.reason)" 
  64. }  
  65.  
  66. # should show 3 again.  
  67. write-host "Available runspaces: $($pool.GetAvailableRunspaces())" 

Feel free to post questions or requests for clarification, but I did say it was a bit tough and developer-oriented. I have a hint that our good friend and fellow MVP, Karl Prosser (aka Klumsy), will be wrapping up some of this stuff into some nice admin-oriented background  command functions.

IMPORTANT:

Due to the WaitAll call at line 40, this script will not work in an STA thread (i.e. in PowerShell ISE). Use PowerShell.EXE to run this script. Everything else will work in ISE fine.

Have fun!

PowerShell CTP3 and Module Manifests

A module manifest file is a PowerShell data file (.psd1) with the same name as the module directory. For example, the FileTransfer module installed with CTP3 -- which contains Cmdlets for BITS -- is in a directory called $pshome\Modules\FileTransfer and contains a manifest file called $pshome\Modules\FileTransfer\FileTransfer.psd1. Module manifests are optional, but highly recommended.

A module manifest contains a hashtable declared using the @{} hashtable literal syntax. Valid keys are listed in the following table:

Key

Required

Type

Description

ModuleToProcess

Optional

String

Script module or binary module file associated with this manifest which also becomes the root module for nested modules. If no module is specified, the manifest itself becomes the root module for nested modules.

A binary module is the new name for a snap-in DLL. v1 style snapins can be loaded this way, without having to register them first with installutil.exe; A binary module does NOT need a PSSnapIn class defined.

ModuleVersion

Required

String convertible to System.Version

Version of the module

GUID

Optional

String

Unique identifier for the module which can be used to verify against the module name

Author

Optional

String

Identifies the author of the module

CompanyName

Optional

String

Identifies the company that created the module

Copyright

Optional

String

Module copyright

Description

Optional

String

Describes the contents of the module

PowerShellVersion

Optional

String convertible to System.Version

Minimum required version of the PowerShell engine

CLRVersion

Optional

String convertible to System.Version

Minimum required version of the CLR

RequiredModules

Optional

List of module names

List of modules that must already be loaded globally (note: required modules are not loaded automatically - this could optionally be done using a script in ScriptsToProcess).

RequiredAssemblies

Optional

String array

List of assemblies that will be loaded using the same algorithm as Add-Type

ScriptsToProcess

Optional

String array

Identifies the list of scripts to process when the module is imported. These scripts are dot sourced into the caller’s environment. Only .ps1 files can be specified.

TypesToProcess

Optional

String array

List of .ps1xml type files to process using Update-TypeData

FormatsToProcess

Optional

String array

List of .ps1xml format files to process using Update-FormatData

NestedModules

Optional

String array

List of .ps1, .psm1, .psd1, and .dll files to process on Import-Module. Files are processed in the order listed. DLLs are scraped for cmdlets/providers and .ps1 script files are dot sourced into the module’s session state.

ExportedFunctions

Optional

String array, wildcards supported

List of functions to export. If not defined or if asterisk is specified, all functions imported from nested modules are re‑exported. To prevent export, use the empty string ‘’.

ExportedCmdlets

Optional

String array, wildcards supported

List of cmdlets to export. If not defined or if asterisk is specified, all cmdlets imported from nested modules are re‑exported. To prevent export, use the empty string ‘’.

A big change in CTP3 is that binary Cmdlets can now be scoped – previously they were always global.

ExportedVariables

Optional

String array, wildcards supported

List of variables to export. If not defined or if asterisk is specified, all variables imported from nested modules are re‑exported. To prevent export, use the empty string ‘’.

ExportedAliases

Optional

String array, wildcards supported

List of aliases to export. If not defined or if asterisk is specified, all aliases imported from nested modules are re‑exported. To prevent export, use the empty string ‘’.

PrivateData

Optional

Object

Data to be passed to the module via the manifest file.

I’ve highlighted certain things in the description that are important to note. These are the things that might trip you up.

Have fun!

PowerShell One Liner: Listing known language keywords in CTP3

Meson tweeted a request asking if it was possible to get a list of language keywords from PowerShell itself. The answer is officially “No,” but like most things of this nature, there’s always a sneaky way:

  1. [type]::gettype("System.Management.Automation.KeywordTokenReader")|%{$_.InvokeMember("_keywordTokens", "NonPublic,Static,GetField", $null, $_,@())}  

More interestingly this list turned up a new script keyword, dynamicparam. I haven’t seen it in action yet but it sounds like another “advanced function” feature to bring functions and cmdlets closer to parity. I may need to add another article to my dynamic parameter series ;-)

List of Type Accelerators for PowerShell CTP3

This is an interesting exercise to show the power of PowerShell’s language to explore and manipulate object models, specifically its own. You all should be familiar with Type Accelerators: The short name syntax for accessing commonly used .NET Types. An example would be [wmi] – this is the same as typing [System.Management.ManagementObject]. So, how can we find all of the current existing Type Accelerators? Well, after cracking open PowerShell with our favourite decompilation tool, Reflector, the class in question is System.Management.Automation.TypeAccelerators. Here’s what it looks like:

  1. internal static class TypeAccelerators  
  2. {  
  3.     // Fields  
  4.     private static Dictionary<string, Type> allTypeAccelerators;  
  5.     internal static Dictionary<string, Type> builtinTypeAccelerators;  
  6.     internal static Dictionary<string, Type> userTypeAccelerators;  
  7.  
  8.     // Methods  
  9.     static TypeAccelerators();  
  10.     public static void Add(string typeName, Type type);  
  11.     internal static void FillCache(Dictionary<string, Type> cache);  
  12.     internal static string FindBuiltinAccelerator(Type type);  
  13.     public static bool Remove(string typeName);  
  14.  
  15.     // Properties  
  16.     public static Dictionary<string, Type> Get { get; }  
  17. }  
  18.  

Interestingly, the methods that let you add and remove your own accelerators are marked Public. The Type itself is internal, but the dictionary named “userTypeAccelerators” is positively tantalizing. It looks like perhaps the team have plans to let people add their own accelerators! Then again, this is a CTP, and this may change in the future. Well, let’s see if we can finish off what the team half started ;-)

First thing we need to do is get a reference to the internal class. The C# heads amongst you will start thinking about using reflection to get your hands on the type, but actually there’s an easier way. PowerShell’s language is incredibly flexible and through sneakiness, you can use System.Type’s GetType method to invoke any public method without reverting to tricky reflection calls. First of all, lets add our own user-defined Type Accelerator which is aliased to this internal class itself:

  1. # get a reference to the Type   
  2. $acceleratorsType = [type]::gettype("System.Management.Automation.TypeAccelerators")  
  3.  
  4. # add an accelerator for this type ;-)  
  5. $acceleratorsType::Add("accelerators", $acceleratorsType)  
  6.  
  7. # will return all built-in accelerators (property)  
  8. [accelerators]::get 
  9.  
  10. # add a user-defined accelerator  
  11. [accelerators]::add([string], [type])  
  12.  
  13. # remove a user-defined accelerator  
  14. [accelerators]::remove([string])  

I’ve split the Type retrieval and Add methods into two lines for brevity. The parser is actually flexible enough to understand the more pithy ([type]::gettype("System.Management.Automation.TypeAccelerators"))::Add(…).

So what do we have in CTP3?

Name Type
int System.Int32
long System.Int64
string System.String
char System.Char
bool System.Boolean
byte System.Byte
double System.Double
decimal System.Decimal
float System.Single
single System.Single
regex System.Text.RegularExpressions.Regex
array System.Array
xml System.Xml.XmlDocument
scriptblock System.Management.Automation.ScriptBlock
switch System.Management.Automation.SwitchParameter
hashtable System.Collections.Hashtable
type System.Type
ref System.Management.Automation.PSReference
psobject System.Management.Automation.PSObject
pscustomobject System.Management.Automation.PSObject
psmoduleinfo System.Management.Automation.PSModuleInfo
powershell System.Management.Automation.PowerShell
runspacefactory System.Management.Automation.Runspaces.RunspaceFactory
runspace System.Management.Automation.Runspaces.Runspace
ipaddress System.Net.IPAddress
wmi System.Management.ManagementObject
wmisearcher System.Management.ManagementObjectSearcher
wmiclass System.Management.ManagementClass
adsi System.DirectoryServices.DirectoryEntry
adsisearcher System.DirectoryServices.DirectorySearcher
accelerators System.Management.Automation.TypeAccelerators

Btw, I generated the above list with this one liner:

  1. [accelerators]::Get.getenumerator() | `  
  2.     select @{Name="Name"; expression={$_.key}},  
  3.            @{name="Type"; expression={$_.value}} | `  
  4.     convertto-html -fragment > .\accelerators.html  

Have fun!

The Twelve days of PowerShell 2.0 CTP3!

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 

PowerShell 2.0 CTP3 has arrived!

To quote the completely understated download blurb:

Windows PowerShell V2 CTP3 introduces several significant features to Windows PowerShell 1.0 and Windows PowerShell V2 CTPs that extends its use, improves its usability, and allows you to control and manage the Windows environment more easily and comprehensively.

The release notes are quite extensive. Here is the section on breaking changes from CTP2:

Breaking Changes to Windows PowerShell V2 (CTP2)

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

  • Following cmdlets have been renamed
    • Add-Module to Import-Module
    • Get-Event to Get-WinEvent
    • *-Runspace to *-PSSession
    • Push-Runspace to Enter-PSSession
    • Pop-Runspace to Exit-PSSession
    • *-PSEvent to *-Event
    • Register-PSEvent to Register-EngineEvent
    • *-PSTransaction to *-Transaction
    • *-PSJob to *-Job
    • *-PSEventSubscriber to *-EventSubscriber
    • *-Bite to *-FileTransfer

  • Following parameters have been renamed
    • Import-LocalizedData: Culture to UICulture
    • Invoke-Command: Runspace to Session, Shell to ConfigurationName
    • Get-Job: SessionId to Id
    • Receive-Job: Runspace to Session, SessionId to Id
    • Remove-Job: SessionId to Id
    • Start-Job: Command to Scriptblock
    • Stop-Job: SessionId to Id
    • Wait-Job: SessionId to Id
    • Get-PSSession: RemoteRunspaceID to InstanceId, SessionId to Id
    • New-PSSession: Runspace to Session, Shell to ConfigurationName
    • Enter-PSSession: Runspace to Session, RemoteRunspaceID to InstanceId, SessionId to Id, Shell to ConfigurationName
    • Remove-PSSession: Runspace to Session, RemoteRunspaceID to InstanceId, SessionId to Id

  • Following parameters have been deleted
    • Export-ModuleMember: Update, ExportList
    • Set-Service: Include, Exclude

  • Following variables have been renamed
    • $CommandLineParameters to $PSBoundParameters
    • $PSPackagePath to $PSModulePath

  • Packages have been renamed to Modules. Packages folder is now renamed to Modules folder. A module imported into another module is now treated as a nested module instead of a peer module. This allows a new module to wrap or repackage one or more existing modules.

  • "Script cmdlets" have been renamed to "advanced functions." The “cmdlet” keyword has been replaced with the “function” keyword. For script cmdlet functionality, use CmdletBinding attribute in the function’s param block. For more information, see about_functions_advanced.
  • The Config-WSMan.ps1 script in the $pshome directory has been replaced by the Enable-PSRemoting function. To configure your system for WS-Management remoting, use the following command:

Enable-PSRemoting –force

Note: If you have upgraded from the Windows PowerShell V2 CTP2 release to the Windows PowerShell V2 CTP3 release, to configure your system for WS-Management remoting, type:

Unregister-PSSessionConfiguration * -force;

Register-PSSessionConfiguration Microsoft.PowerShell –force;

Enable-PSRemoting –force

  • In the Out-GridView cmdlet, the drop-down list used to filter objects is now called “Query” instead of “Filter”.

  • The following changes have been made to Windows PowerShell Integrated Scripting Environment (ISE):
    • The name of the application has changed from “Graphical Windows PowerShell” to “Windows PowerShell Integrated Scripting Environment (ISE)”
    • The executable name has changed from “gpowershell.exe” to “powershell_ise.exe”
    • The profile name has changed from “\Users\<username>\Documents\WindowsPowerShell\Microsoft.GPowerShell_profile.ps1” to “\Users\<username>\Documents\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1”
    • The term “runspace” has been replaced with “PowerShell tab”.

Get it from http://www.microsoft.com/downloads/details.aspx?FamilyID=c913aeab-d7b4-4bb1-a958-ee6d7fe307bc – piping hot!

Quickstart #3: Dynamic Parameters 2 of 3 – Runtime Defined Parameters

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!

PowerScripting Podcast: The Big Two

The dynamic duo / masterminds of PowerShell will be cornered and fiercely grilled by none other than our very own master podcaster, Hal Rottenberg this Thursday.  From the mouth of the suffixed one himself:

Coming up on the PowerScripting Live show this Thursday will be Jeffrey Snover,
the architect for PowerShell as I’m sure you all know, and he’ll be accompanied
by none other than Bruce Payette, author of PowerShell in Action and a core
developer on the PowerShell team.

We’re excited and we hope you can make it this Thursday at 9pm EST!

The live stream address is http://www.ustream.tv/channel/powerscripting-podcast

So if you want to get the lowdown on CTP3 (maybe), join us, the unwashed masses as we clamour to be near our idols. A lock of their hair and a signed discarded printout of directions to building 18 could be yours!

I made that last bit up. Who cares! This is going to be cool! Join us!

Unit Testing SharePoint Code without SharePoint

Now this is cool. I’ve always wanted to try out TDD, but as I’m primarily a SharePoint developer, a lot of the time my code is written on my laptop running XP, so I can’t actually test anything since SharePoint won’t install there. The folks at Bamboo Solutions came up with some clever hacks to get WSS 3.0 and MOSS running on Vista, but it’s a bit of a heavyweight solution, especially when you consider this:

Typemock are offering their new product for unit testing SharePoint called Isolator For SharePoint, for a special introduction price. it is the only tool that allows you to unit test SharePoint without a SharePoint server. To learn more click here.

The first 50 bloggers who blog this text in their blog and tell us about it, will get a Full Isolator license, Free. for rules and info click here.

Unfortunately the competition is actually over, but it’s still worth a peek!

About the author

Irish, PowerShell MVP, .NET/ASP.NET/SharePoint Developer, Budding Architect. Developer. Montrealer. Opinionated. Montreal, Quebec.

Month List

Page List