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