header
header Register : : Login header
header
divider
menuleft
menuright
submenu
left
Cmdlet Extension Library
Category: Windows general
Contributed by Kirk Munro (Poshoholic) on 2007-11-27, last updated 2008-01-15 • user rating: 5


Description:
This script contains a library of useful functions and will grow over time. In its current revision its purpose is as follows: 1. To extend Get-Help so that the cmdlet help documentation for core cmdlets includes all dynamic parameter information as well. 2. To provide Get-PSResourceString to help support script internationalization. 3. To provide Invoke-Member to help ease the invocation of members within a pipeline. 4. To provide a version of Should-Process that supports localized PowerShell. Note that when extending cmdlets I have tried to ensure that the original cmdlet and the corresponding cmdlet extension function can be used interchangeably in scripts without requiring any modifications. The only known exception to this is when scripts are modified to explicitly use some information that is only exposed by the function extending the cmdlet. Also I have made an effort to support localized versions of PowerShell in these functions as well by using the resource strings that come with PowerShell for the current culture through the Get-PSResourceString cmdlet. There are a few strings that will still only be available in English though, such as variable and alias descriptions.

Non-core snapins required to run this:
None

Formatted code:
1 ######################################################################################################################## 2 #                                                                                                                      # 3 # File:             CmdletExtensionLibrary.ps1                                                                         # 4 # Author:           Kirk Munro                                                                                         # 5 # Author's Blog:    http://poshoholic.com                                                                              # 6 # Revision:         1.0.3                                                                                              # 7 # Contents:         A collection of functions designed with two purposes in mind:                                      # 8 #                   1. To seamlessly extend published cmdlet functionality transparently to the end user               # 9 #                   2. To wrap common operations in fully documented, well named functions designed to extend          # 10 #                      PowerShell's core set of features                                                               # 11 #                   In the first case, every effort is made to ensure that the original cmdlet and the corresponding   # 12 #                   function can be used interchangeably in scripts without requiring any modifications. The only      # 13 #                   known exception to this is when scripts are modified to explicitly use some information that is    # 14 #                   only exposed by the function extending the cmdlet.                                                 # 15 #                   In the second case, functionality is being exposed as functions to solicit community feedback. It  # 16 #                   is my intention to publish these sorts of functions as cmdlets in the future.                      # 17 # History:          v1.0.0 - Initial release designed to enhance support for dynamic parameters in the PowerShell help # 18 #                            system                                                                                    # 19 #                   v1.0.1 - Addition of Invoke-Member function to allow users to invoke any member on a data set      # 20 #                            without having to use ForEach-Object                                                      # 21 #                   v1.0.2 - Fixed grs alias for Get-PSResourceString                                                  # 22 #                          - Added ... alias for Invoke-Member                                                         # 23 #                          - Added pipeline support to Invoke-Cmdlet, Add-PSSnapin, Remove-PSSnapin and Get-Help       # 24 #                   v1.0.3 - Added retrieval of Microsoft.PowerShell.ConsoleHost strings to Get-PSResourceString       # 25 #                          - Added -list parameter to Get-PSResourceString                                             # 26 #                          - Added more examples to Get-PSResourceString documentation (comments)                      # 27 #                          - Added Should-Process function to provide -whatif, -confirm and -verbose support to other  # 28 #                            functions                                                                                 # 29 #                          - Added -whatif, -confirm and -verbose support to Invoke-Member function                    # 30 #                                                                                                                      # 31 ######################################################################################################################## 32 33 ######################################################################################################################## 34 # NAME 35 #     Get-PSResourceString 36 # 37 # SYNOPSIS 38 #     Returns a resource string that is looked up in the System.Management.Automation namespace or the 39 #     Microsoft.PowerShell.ConsoleHost namespace, or a list of resource root names or resource identifiers that are 40 #     available. 41 # 42 # SYNTAX 43 #     Get-PSResourceString [-baseName] <string> [-resourceId] <string> [[-defaultValue] <string>] 44 #     [[-culture] <System.Globalization.CultureInfo>] 45 #     Get-PSResourceString [[-baseName] <string>] -list 46 # 47 # DETAILED DESCRIPTION 48 #     The Get-PSResourceString function returns a resource string that is looked up in the System.Management.Automation 49 #     namespace or the Microsoft.PowerShell.ConsoleHost namespace, or a list of resource root names or resource 50 #     identifiers that are available. If a resource string was requested and it is not found, the default value (if 51 #     present) will be returned. 52 # 53 # PARAMETERS 54 #     -baseName <string> 55 #         Specifies the root name of the resources. 56 # 57 #         Required?                    true 58 #         Position?                    1 59 #         Default value 60 #         Accept pipeline input?       false 61 #         Accept wildcard characters?  false 62 # 63 #     -resourceId <string> 64 #         Specifies the identifier of the resource that is being retrieved. 65 # 66 #         Required?                    true 67 #         Position?                    2 68 #         Default value 69 #         Accept pipeline input?       false 70 #         Accept wildcard characters?  false 71 # 72 #     -defaultValue <string> 73 #         Specifies the default value for the resource string. If the string is not found, the default value will be 74 #         returned. 75 # 76 #         Required?                    false 77 #         Position?                    3 78 #         Default value                null 79 #         Accept pipeline input?       false 80 #         Accept wildcard characters?  false 81 # 82 #     -culture <System.Globalization.CultureInfo> 83 #         Specifies the culture to use when looking up the resource string. 84 # 85 #         Required?                    false 86 #         Position?                    4 87 #         Default value                $host.CurrentCulture 88 #         Accept pipeline input?       false 89 #         Accept wildcard characters?  false 90 # 91 #     -list <Switch> 92 #         When this parameter is used by itself, this function outputs the root names that are available. When this 93 #         parameter is used in conjunction with the baseName parameter, this function outputs the resource identifiers 94 #         that are availab.e 95 # 96 #         Required?                    false 97 #         Position?                    named 98 #         Default value                false 99 #         Accept pipeline input?       false 100 #         Accept wildcard characters?  false 101 # 102 # INPUT TYPE 103 #     String,System.Globalization.CultureInfo,Switch 104 # 105 # RETURN TYPE 106 #     String,String[] 107 # 108 # NOTES 109 #     For more information the System.Globalization.CultureInfo type consult the relevant MSDN documentation. 110 # 111 #     -------------------------- EXAMPLE 1 -------------------------- 112 # 113 #     C:\PS>get-psresourcestring -list 114 # 115 # 116 #     This command retrieves the list of resource root names that are available. 117 # 118 # 119 #     -------------------------- EXAMPLE 2 -------------------------- 120 # 121 #     C:\PS>get-psresourcestring -basename helpdisplaystrings -list 122 # 123 # 124 #     This command retrieves the list of resource strings in the resource root called 'helpdisplaystrings' using the 125 #     current culture. 126 # 127 # 128 #     -------------------------- EXAMPLE 3 -------------------------- 129 # 130 #     C:\PS>get-psresourcestring -list | foreach-object { get-psresourcestring -basename $_ -list } 131 # 132 # 133 #     This command retrieves all resource strings that are available using the current culture. 134 # 135 # 136 #     -------------------------- EXAMPLE 4 -------------------------- 137 # 138 #     C:\PS>get-psresourcestring -basename helpdisplaystrings -resourceid falseshort 139 # 140 # 141 #     This command retrieves the string associated with the 'falseshort' resource id using the current culture. 142 # 143 # 144 145 Function Get-PSResourceString { 146 param( 147 [string]$baseName = $null, 148 [string]$resourceId = $null, 149 [string]$defaultValue = $null, 150 [System.Globalization.CultureInfo]$culture = $host.CurrentCulture, 151 [Switch]$list 152 ) 153 154 if ($list -and ($resourceId -or $defaultValue)) { 155 throw $(Get-PSResourceString -BaseName 'ParameterBinderStrings' -ResourceId 'AmbiguousParameterSet') 156 } 157 158 if ($list) { 159 $engineAssembly = [System.Reflection.Assembly]::GetExecutingAssembly() 160 $hostAssembly = [System.Reflection.Assembly]::LoadWithPartialName('Microsoft.PowerShell.ConsoleHost') 161 if ($baseName) { 162 $engineAssembly.GetManifestResourceNames() | Where-Object { $_ -eq "$baseName.resources" } | ForEach-Object { 163 $resourceManager = New-Object -TypeName System.Resources.ResourceManager($baseName, $engineAssembly) 164 $resourceManager.GetResourceSet($host.CurrentCulture,$true,$true) | Add-Member -Name BaseName -MemberType NoteProperty -Value $baseName -Force -PassThru | ForEach-Object { 165 $_.PSObject.TypeNames.Clear() 166 $_.PSObject.TypeNames.Add('ResourceString') 167 $_ | Write-Output 168 } 169 } 170 $hostAssembly.GetManifestResourceNames() | Where-Object { $_ -eq "$baseName.resources" } | ForEach-Object { 171 $resourceManager = New-Object -TypeName System.Resources.ResourceManager($baseName, $hostAssembly) 172 $resourceManager.GetResourceSet($host.CurrentCulture,$true,$true) | Add-Member -Name BaseName -MemberType NoteProperty -Value $baseName -Force -PassThru | ForEach-Object { 173 $_.PSObject.TypeNames.Clear() 174 $_.PSObject.TypeNames.Add('ResourceString') 175 $_ | Write-Output 176 } 177 } 178 } else { 179 $engineAssembly.GetManifestResourceNames() | Where-Object { $_ -match '\.resources$' } | ForEach-Object { $_.Replace('.resources','') } 180 $hostAssembly.GetManifestResourceNames() | Where-Object { $_ -match '\.resources$' } | ForEach-Object { $_.Replace('.resources','') } 181 } 182 } else { 183 if (-not $baseName) { 184 throw $($(Get-PSResourceString -BaseName 'ParameterBinderStrings' -ResourceId 'ParameterArgumentValidationErrorNullNotAllowed') -f $null,'BaseName') 185 } 186 if (-not $resourceId) { 187 throw $($(Get-PSResourceString -BaseName 'ParameterBinderStrings' -ResourceId 'ParameterArgumentValidationErrorNullNotAllowed') -f $null,'ResourceId') 188 } 189 if (-not $global:PSResourceStringTable) { 190 $engineAssembly = [System.Reflection.Assembly]::GetExecutingAssembly() 191 $hostAssembly = [System.Reflection.Assembly]::LoadWithPartialName('Microsoft.PowerShell.ConsoleHost') 192 if ($engineAssembly.GetManifestResourceNames() -contains "$baseName.resources") { 193 New-Variable -Scope Global -Name PSResourceStringTable -Value @{} -Description 'A cache of PowerShell resource strings. To access data in this table, use Get-ResourceString.' 194 $global:PSResourceStringTable['EngineAssembly'] = @{'Assembly'=$engineAssembly;'Cultures'=@{}} 195 $global:PSResourceStringTable['HostAssembly'] = @{'Assembly'=$hostAssembly;'Cultures'=@{}} 196 $resourceManager = (New-Object -TypeName System.Resources.ResourceManager($baseName, $global:PSResourceStringTable.EngineAssembly.Assembly)); 197 $global:PSResourceStringTable.EngineAssembly.Cultures[$culture.Name] = @{$baseName=@{'ResourceManager'=$resourceManager;'Strings'=$resourceManager.GetResourceSet($culture,$true,$true)}}; 198 } elseif ($hostAssembly.GetManifestResourceNames() -contains "$baseName.resources") { 199 New-Variable -Scope Global -Name PSResourceStringTable -Value @{} -Description 'A cache of PowerShell resource strings. To access data in this table, use Get-ResourceString.' 200 $global:PSResourceStringTable['EngineAssembly'] = @{'Assembly'=$engineAssembly;'Cultures'=@{}} 201 $global:PSResourceStringTable['HostAssembly'] = @{'Assembly'=$hostAssembly;'Cultures'=@{}} 202 $resourceManager = (New-Object -TypeName System.Resources.ResourceManager($baseName, $global:PSResourceStringTable.HostAssembly.Assembly)); 203 $global:PSResourceStringTable.HostAssembly.Cultures[$culture.Name] = @{$baseName=@{'ResourceManager'=$resourceManager;'Strings'=$resourceManager.GetResourceSet($culture,$true,$true)}}; 204 } 205 } elseif ($global:PSResourceStringTable.EngineAssembly.Assembly.GetManifestResourceNames() -contains "$baseName.resources") { 206 if (-not $global:PSResourceStringTable.EngineAssembly.Cultures.ContainsKey($culture.Name)) { 207 $resourceManager = (New-Object -TypeName System.Resources.ResourceManager($baseName, $global:PSResourceStringTable.EngineAssembly.Assembly)); 208 $global:PSResourceStringTable.EngineAssembly.Cultures[$culture.Name] = @{$baseName=@{'ResourceManager'=$resourceManager;'Strings'=$resourceManager.GetResourceSet($culture,$true,$true)}}; 209 } elseif (-not $global:PSResourceStringTable.EngineAssembly.Cultures[$culture.Name].ContainsKey($baseName)) { 210 $resourceManager = (New-Object -TypeName System.Resources.ResourceManager($baseName, $global:PSResourceStringTable.EngineAssembly.Assembly)); 211 $global:PSResourceStringTable.EngineAssembly.Cultures[$culture.Name][$baseName] = @{'ResourceManager'=$resourceManager;'Strings'=$resourceManager.GetResourceSet($culture,$true,$true)}; 212 } 213 } elseif ($global:PSResourceStringTable.HostAssembly.Assembly.GetManifestResourceNames() -contains "$baseName.resources") { 214 if (-not $global:PSResourceStringTable.HostAssembly.Cultures.ContainsKey($culture.Name)) { 215 $resourceManager = (New-Object -TypeName System.Resources.ResourceManager($baseName, $global:PSResourceStringTable.HostAssembly.Assembly)); 216 $global:PSResourceStringTable.HostAssembly.Cultures[$culture.Name] = @{$baseName=@{'ResourceManager'=$resourceManager;'Strings'=$resourceManager.GetResourceSet($culture,$true,$true)}}; 217 } elseif (-not $global:PSResourceStringTable.HostAssembly.Cultures[$culture.Name].ContainsKey($baseName)) { 218 $resourceManager = (New-Object -TypeName System.Resources.ResourceManager($baseName, $global:PSResourceStringTable.HostAssembly.Assembly)); 219 $global:PSResourceStringTable.HostAssembly.Cultures[$culture.Name][$baseName] = @{'ResourceManager'=$resourceManager;'Strings'=$resourceManager.GetResourceSet($culture,$true,$true)}; 220 } 221 } 222 223 $resourceString = $null 224 if ($global:PSResourceStringTable) { 225 if ($global:PSResourceStringTable.EngineAssembly.Cultures -and $global:PSResourceStringTable.EngineAssembly.Cultures.ContainsKey($culture.Name) -and $global:PSResourceStringTable.EngineAssembly.Cultures[$culture.Name].ContainsKey($baseName)) { 226 $resourceString = ($global:PSResourceStringTable.EngineAssembly.Cultures[$culture.Name][$baseName].Strings | Where-Object { $_.Name -eq $resourceId }).Value 227 } elseif ($global:PSResourceStringTable.HostAssembly.Cultures -and $global:PSResourceStringTable.HostAssembly.Cultures.ContainsKey($culture.Name) -and $global:PSResourceStringTable.HostAssembly.Cultures[$culture.Name].ContainsKey($baseName)) { 228 $resourceString = ($global:PSResourceStringTable.HostAssembly.Cultures[$culture.Name][$baseName].Strings | Where-Object { $_.Name -eq $resourceId }).Value 229 } 230 } 231 if (-not $resourceString) { 232 $resourceString = $defaultValue 233 } 234 235 return $resourceString 236 } 237 } 238 239 if (-not (Get-Alias -Name grs -ErrorAction SilentlyContinue)) { 240 New-Alias -Name grs -Value Get-PSResourceString -Description 'Returns a resource string that is looked up in the System.Management.Automation namespace.' 241 } 242 243 ######################################################################################################################## 244 # NAME 245 #     Should-Process 246 # 247 # SYNOPSIS 248 #     Determines whether the specified operation should be performed on the target object. 249 # 250 # SYNTAX 251 #     Should-Process [-operation] <string> [-target] <string> [-whatIf] 252 #     Should-Process [-operation] <string> [-target] <string> [-confirmResponse] <REF> [[-confirmPrompt] <string>] 253 #     [-confirm] 254 #     Should-Process [-operation] <string> [-target] <string> [-verbose] 255 # 256 # DETAILED DESCRIPTION 257 #     Determines whether the specified operation should be performed on the target object. Returns true if the operation 258 #     should be performed. Should-Process never performs the operation; it just indicates whether or not it should be 259 #     performed to the caller. If the whatIf switch is used, Should-Process outputs strings indicating what it would do 260 #     if whatIf wasn't used. If the confirm switch is used, Should-Process asks the user to confirm that they want to 261 #     perform the operation. If the verbose switch is used, Should-Process writes verbose output for each operation that 262 #     will be performed on each target. 263 # 264 # PARAMETERS 265 #     -operation <string> 266 #         Specifies the name of the function that was invoked. 267 # 268 #         Required?                    true 269 #         Position?                    1 270 #         Default value 271 #         Accept pipeline input?       false 272 #         Accept wildcard characters?  false 273 # 274 #     -target <string> 275 #         Specifies the identifier of the object that is being used in the operation. 276 # 277 #         Required?                    true 278 #         Position?                    2 279 #         Default value 280 #         Accept pipeline input?       false 281 #         Accept wildcard characters?  false 282 # 283 #     -confirmResponse <REF> 284 #         Reference variable that retains any confirm question response that applies to all objects being processed. 285 # 286 #         Required?                    true 287 #         Position?                    3 288 #         Default value 289 #         Accept pipeline input?       false 290 #         Accept wildcard characters?  false 291 # 292 #     -confirmPrompt <string> 293 #         Specifies the string that will be displayed to the caller when the -confirm switch is used. 294 # 295 #         Required?                    false 296 #         Position?                    4 297 #         Default value                Are you sure you want to perform this action? 298 #         Accept pipeline input?       false 299 #         Accept wildcard characters?  false 300 # 301 #     -verbose <switch> 302 #         When this parameter is used, this function outputs verbose information to the host. 303 # 304 #         Required?                    false 305 #         Position?                    named 306 #         Default value 307 #         Accept pipeline input?       false 308 #         Accept wildcard characters?  false 309 # 310 #     -confirm <switch> 311 #         When this parameter is used, this function requests confirmation from the user for the actions it will take. 312 # 313 #         Required?                    false 314 #         Position?                    named 315 #         Default value 316 #         Accept pipeline input?       false 317 #         Accept wildcard characters?  false 318 # 319 #     -whatif <switch> 320 #         When this parameter is used, this function outputs what it would do without actually taking action. 321 # 322 #         Required?                    false 323 #         Position?                    named 324 #         Default value 325 #         Accept pipeline input?       false 326 #         Accept wildcard characters?  false 327 # 328 # INPUT TYPE 329 #     String,Ref,Switch 330 # 331 # RETURN TYPE 332 #     Boolean 333 # 334 # NOTES 335 #     Whatif takes precedence over confirm. Confirm takes precedence over verbose. If more than one switch parameter is 336 #     used, this precedence order will be followed and only the highest precedence switch will be used. 337 # 338 #     The ConfirmResponse reference parameter is used to determine if "YES to All" or "NO to all" has been previously 339 #     selected. 340 # 341 #     When using Should-Process inside of functions that can be used in a pipeline, you should initialize your reference 342 #     variable in the begin block and then call Should-Process in the process block. 343 # 344 #     -------------------------- EXAMPLE 1 -------------------------- 345 # 346 # 347 #  C:\PS>function Stop-Calc ([Switch]$Verbose, [Switch]$Confirm, [Switch]$Whatif) { 348 #         $ConfirmResponse = $null 349 #         foreach ($p in Get-Process calc) { 350 #             if (Should-Process Stop-Calc $p.Id ([REF]$ConfirmResponse) ` 351 #                 -Verbose:$Verbose -Confirm:$Confirm -Whatif:$Whatif) { 352 #                 Stop-Process $p.Id 353 #             } 354 #         } 355 #     } 356 #     C:\PS>stop-calc -confirm 357 # 358 # 359 #     This prompts you to confirm you want to stop all calc processes when using the simple Stop-Process function. 360 # 361 # 362 # RELATED LINKS 363 #     about_commonparameters 364 #     about_ref 365 # 366 367 Function Should-Process { 368 param( 369 [string]$Operation = $(throw $($(Get-PSResourceString -BaseName 'ParameterBinderStrings' -ResourceId 'ParameterArgumentValidationErrorNullNotAllowed') -f $null,'Operation')), 370 [string]$Target = $(throw $($(Get-PSResourceString -BaseName 'ParameterBinderStrings' -ResourceId 'ParameterArgumentValidationErrorNullNotAllowed') -f $null,'Target')), 371 [REF]$ConfirmResponse = ([REF]$null), 372 [string]$ConfirmPrompt = $($(Get-PSResourceString -BaseName 'CommandBaseStrings' -ResourceId 'ShouldProcessWarningFallback') -f $null), 373 [Switch]$Verbose, 374 [Switch]$Confirm, 375 [Switch]$Whatif