Trap remove-item exception - powershell

In powershell there is some exception that I am not able to trap or I am not doing to correct things.
So here is the code that does the things:
log "Processing $($_.Name).old" $logFile
if (Test-Path "$($_.Name).old" )
{
& {
rm "$($_.Name).old"
}
trap #[System.UnauthorizedAccessException]
{
log "Move to trash" $logFile
moveTrach "$($_.Name).old"
continue
}
}
I had comment out the type in the trap expression to be sure to catch anything.
But unfortunately I never go into the trap clause.
I can see the exception log but not the "Move to trash" log.
2012-02-16 10:35:31 Processing file.dll
Remove-Item : Cannot remove item file.dll.old: Access to the path 'file.dll.old' is denied.
At upgradegw.ps1:189 char:29
+ rm <<<< "$($_.Name).old"
+ CategoryInfo : PermissionDenied: (file.dll.old:FileInfo) [Remove-Item], UnauthorizedAccessException
+ FullyQualifiedErrorId : RemoveFileSystemItemUnAuthorizedAccess,Microsoft.PowerShell.Commands.RemoveItemCommand
2012-02-16 10:35:31 Processing file2.dll

The trap will only trigger on a terminating error.
rm "$($_.Name).old" -ErrorAction "Stop"

Related

Does the hashtable's Add method for duplicate keys return a terminating or non-terminating exception when using catch?

When adding a duplicate key to a hashtable using the add method, a MethodInvocationException arises:
50|PS(5.1.19041) C:\Users [220908-11:58:48]> $h = #{}
51|PS(5.1.19041) C:\Users [220908-11:58:51]> $h.add('a',$null)
52|PS(5.1.19041) C:\Users [220908-11:58:53]> $h.add('a',$null)
Exception calling "Add" with "2" argument(s): "Item has already been added. Key in dictionary: 'a' Key being added: 'a'"
At line:1 char:1
+ $h.add('a',$null)
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentException
I prepared a couple of functions to test whether this is a non-terminating or terminating error. The results seem conflicting. Here is my first function and test run:
function test-ht {
[cmdletbinding()]
param(
[hashtable]$ht,
[string]$addKey,
[string]$addValue,
[string]$msg
)
$ht.Add( $addKey, $addValue )
write-host "finished $msg"
}
$hash = #{}
test-ht -ht $hash -addKey 'test' -addValue '1' -msg 'trial 1'
test-ht -ht $hash -addKey 'test' -addValue '2' -msg 'trial 1 err'
test-ht -ht $hash -addKey 'test' -addValue '3' -msg 'trial 1 stop' -ErrorAction Stop
This outputs:
finished trial 1
Exception calling "Add" with "2" argument(s): "Item has already been added. Key in dictionary: 'test' Key being added: 'test'"
At line:10 char:5
+ $ht.Add( $addKey, $addValue )
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentException
finished trial 1 err
test-ht : Exception calling "Add" with "2" argument(s): "Item has already been added. Key in dictionary: 'test' Key being added: 'test'"
At line:18 char:1
+ test-ht -ht $hash -addKey 'test' -addValue '3' -msg 'trial 1 stop' -E ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [test-ht], MethodInvocationException
+ FullyQualifiedErrorId : ArgumentException,test-ht
The 2nd command with -msg 'trial 1 err' seems to suggest it is a non-terminating error: the function prints the exception but still writes out its finished message. When I force it to -ErrorAction Stop, the finished message does not appear. This seems like normal behavior for a non-terminating error to me.
Then I run the second test, which is the same as above, except the .Add method is embedded in a try/catch statement:
function test-ht2 {
[cmdletbinding()]
param(
[hashtable]$ht,
[string]$addKey,
[string]$addValue,
[string]$msg
)
try {$ht.Add( $addKey, $addValue )} catch{}
write-host "finished $msg"
}
$hash2 = #{}
test-ht2 -ht $hash2 -addKey 'test' -addValue '1' -msg 'trial 2'
test-ht2 -ht $hash2 -addKey 'test' -addValue '2' -msg 'trial 2 err'
This outputs:
finished trial 2
finished trial 2 err
Here, the catch suppresses the error. This suggests a terminating error to me, as catch does not suppress non-terminating errors, e.g.,
55|PS(5.1.19041) C:\Users [220908-12:05:36]> gci C:/missing; write-host 'finished'
gci : Cannot find path 'C:\missing' because it does not exist.
At line:1 char:1
+ gci C:/missing; write-host 'finished'
+ ~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\missing:String) [Get-ChildItem], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
finished
56|PS(5.1.19041) C:\Users [220908-12:05:42]> try {gci C:/missing; write-host 'finished'} catch {}
gci : Cannot find path 'C:\missing' because it does not exist.
At line:1 char:6
+ try {gci C:/missing; write-host 'finished'} catch {}
+ ~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\missing:String) [Get-ChildItem], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
finished
In summary, in the first run with test-ht, the -msg 'trial 1 err' printed the exception and continued, as if it were non-terminating. In the second run with test-ht2 and the same function calls, the exception is suppressed by catch, as if it were a terminating error.
My questions:
Is this error non-terminating or terminating?
If it is non-terminating, why does the catch suppress the exception message?
If it is terminating, why does test-ht run to completion when adding a duplicate key?
It is terminating:
$x = #{}
try {
$x.add('1',1)
$x.add('1',2)
}
Catch {
write-error "Terminating error"
}
Write-Error: Terminating error
test-ht runs into an exception if you add the 2nd time the same key:
$x =#{}
test-ht -ht $x -addKey a -addValue 2 -msg "haha"
finished haha
test-ht -ht $x -addKey a -addValue 2 -msg "haha"
Exception calling "Add" with "2" argument(s): "Item has already been added. Key in dictionary: 'a' Key being added:....
finished haha
If you add the key before calling the function and after that call the function with the same key it gives you also the error:
$x =#{a=1}
test-ht -ht $x -addKey a -addValue 2 -msg "haha"
Exception calling "Add" with "2" argument(s): "Item has already been added. Key in dictionary: 'a' Key being added:
test-ht2 is running to completion because there is nothing specified in the catch block which would stop the processing. Add return to the catch block to end processing of the script:
function test-ht2 {
[cmdletbinding()]
param(
[hashtable]$ht,
[string]$addKey,
[string]$addValue,
[string]$msg
)
try {$ht.Add( $addKey, $addValue )} catch{return}
write-host "finished $msg"
}
With retrun in the catch it won't output "finished $msg" anymore.
I've recently learned about a 3rd type of error in PowerShell, possibly not documented or not well documented, where it produces an error that doesn't terminate the script but can be caught by try/catch, sort of an ambiguous non-terminating terminating error.
This is perhaps most easily reproduced with the example of dividing by 0.
1 / $null; 'done' #non-terminating behavior: 'done' is still printed.
vs
try { 1 / $null; 'done' }catch{'terminating error caught'} #terminating behavior: error is caught; 'done' is not printed.
The hashtable's .add method appears to fall into this same category. It may be related to exceptions thrown by .NET, as mentioned in this question.

ErrorAction "SilentlyContinue" does not populate ErrorVariable

Issue
When using -ErrorAction "SilentlyContinue", the error variable is not being populated as described in the following documentation: Handling Errors the PowerShell Way.
Question
How to prevent the error to be displayed as it is with -ErrorAction "Continue" yet still populate the error variable?
Bonus question
Is there a way to append the error to the error variable in order to store more than one of them?
MWE
Script
$ErrorActions = #("Continue", "SilentlyContinue", "Stop")
foreach ($ErrorAction in $ErrorActions) {
Write-Host -Object $ErrorAction -ForegroundColor "Green"
Get-Item -Path "C:\tmp\error1" -ErrorAction $ErrorAction -ErrorVariable "ErrorMessage"
Get-Item -Path "C:\tmp\error2" -ErrorAction $ErrorAction -ErrorVariable "ErrorMessage"
Write-Host -Object "ErrorVariable" -ForegroundColor "Yellow"
$ErrorMessage
}
Output
Continue
Get-Item : Cannot find path 'C:\tmp\error1' because it does not exist.
At C:\tmp\mwe.ps1:43 char:5
Get-Item -Path "C:\tmp\error1" -ErrorAction $ErrorAction -ErrorVa ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : ObjectNotFound: (C:\tmp\error1:String) [Get-Item], ItemNotFoundException
FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand
Get-Item : Cannot find path 'C:\tmp\error2' because it does not exist.
At C:\tmp\mwe.ps1:44 char:5
Get-Item -Path "C:\tmp\error2" -ErrorAction $ErrorAction -ErrorVa ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : ObjectNotFound: (C:\tmp\error2:String) [Get-Item], ItemNotFoundException
FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand
ErrorVariable
Get-Item : Cannot find path 'C:\tmp\error2' because it does not exist.
At C:\tmp\mwe.ps1:44 char:5
Get-Item -Path "C:\tmp\error2" -ErrorAction $ErrorAction -ErrorVa ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : ObjectNotFound: (C:\tmp\error2:String) [Get-Item], ItemNotFoundException
FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand
SilentlyContinue
ErrorVariable
Stop
Get-Item : Cannot find path 'C:\tmp\error1' because it does not exist.
At C:\tmp\mwe.ps1:43 char:5
Get-Item -Path "C:\tmp\error1" -ErrorAction $ErrorAction -ErrorVa ...
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : ObjectNotFound: (C:\tmp\error1:String) [Get-Item], ItemNotFoundException
FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand
Using Get-ChildItem as an example:
Get-ChildItem C:\nonexist -EA SilentlyContinue -EV silentErr
[bool]$silentErr # ==> True
As the documentation you linked to mentions, for -ErrorVariable and $ErrorActionPreference controls the following behavior when non-terminating errors occur (these do not affect terminating errors):
Continue: Display the error and continue execution.
SilentlyContinue: Hide error but still add it to the -ErrorVariable, if specified, and $error stack.
Stop: Throws an exception and halts execution. Exceptions may be caught and handled via a try / catch / finally block.
Non-terminating errors cannot be normally handled via try / catch / finally because an exception isn't thrown unless -ErrorAction is Stop.
Ignore: The error is swallowed with no indication it occurred. Neither -ErrorVariable or the $error stack is updated in this case.
Inquire: Ask the operator what to do if an error occurs.
Using the above knowledge, we can still rely on the $error automatic variable and the specified-ErrorVariable to be populated if the -ErrorAction is SilentlyContinue.
Note: You can also use the $ErrorView variable to further control how errors are displayed in the console.
To answer your sub-question, there is not a mechanism for giving a "named" error stack, but you can use the built-in $error stack to keep track of the errors which occur (and didn't occur under-EA Ignore). If you want to ensure you only have errors that occur at a certain point onward in your script/session/etc, you can call the following to clear the error variable:
$error.Clear()
Additional Information
Terminating Errors
Non-Terminating Errors
$ErrorActionPreference preference variable
$Error and $ErrorView automatic variables

PowerShell Try Catch error handling function doesn't show my custom warning message [duplicate]

This question already has an answer here:
How to handle failed variable assignments in powershell? [duplicate]
(1 answer)
Closed 3 years ago.
I am trying to write a simple PowerShell code to create a registry key, then use TRY and CATCH to handle/catch any potential exceptions that may occur. As a test scenario, I am expecting to get "Script failed to create the registry key" if I modify the registry path. Unfortunately, the TRY/CATCH error handling function doesn't work for me and except the error itself nothing shows up in the console.
$NetBTpath = "HKLM:\System\CurrentControlSet\Services\NetBT\Parameters"
$RegValueName = "NodeType"
Try
{
if (((Get-ItemProperty $NetBTpath).PSobject.Properties.Name -contains $RegValueName) -ne "True")
{
New-ItemProperty -Path $NetBTpath -Name "NodeType" -Value 2 -PropertyType "dword"
}
}
Catch [System.Exception]
{
Write-warning "Script failed to create the registry key"
}
It works fine as long as the registry path is correct but if I rename the registry folder ...\NetBT\Parameters to ...\NetBT\Parameters1, I would only see:
Get-ItemProperty : Cannot find path 'HKLM:\System\CurrentControlSet\Services\NetBT\Parameters' because it does not exist.
At C:\temp\NetBT_RegConfig222.ps1:10 char:11
+ if (((Get-ItemProperty $NetBTpath).PSobject.Properties.Name -cont ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (HKLM:\System\Cu...etBT\Parameters:String) [Get-ItemProperty], ItemNotFoundExcep
tion
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemPropertyCommand
New-ItemProperty : Cannot find path 'HKLM:\System\CurrentControlSet\Services\NetBT\Parameters' because it does not exist.
At C:\temp\NetBT_RegConfig222.ps1:12 char:9
+ New-ItemProperty -Path $NetBTpath -Name "NodeType" -Value 2 ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (HKLM:\System\Cu...etBT\Parameters:String) [New-ItemProperty], ItemNotFoundExcep
tion
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.NewItemPropertyCommand
I have already tried to use only Catch {} as well as Catch [System.Management.Automation.ItemNotFoundException].
Please advice.
You need to add the -ErrorAction Stop switch to your Get-ItemProperty and New-ItemProperty lines. Sometimes commands will throw a non-fatal error, and the catch doesn't get invoked. To ensure that you will fall into your catch, add the above switch.

How can I catch an exception from Publish-Module?

I am using Publish-Module and one of the modules had a bad psd1 file. PowerShell threw an exception as expected. The call to Publish-Module is inside a try block but the error handling code in the catch block never ran. It appears that this error is not being caught.
There is another error that happens in this same PowerShell code where the module I am publishing already exists in the repository. When that error occurs the code in the catch block runs and processes the exception. Is there something different about the first exception that would cause the catch block to be bypassed?
Code snippet:
try {
Publish-Module -Path .\$moduleName -Repository MyRepo -NuGetApiKey ghehdue
"Module $moduleName published."
}
catch {
if ($_.Exception.Message -ilike "*cannot be published as the current version*is already available in the repository*") {
"The latest version of module $moduleName already exists in the repository."
}
else {
$exitCode += 1
Write-Error $_
}
}
}
Error that is not caught
Microsoft.PowerShell.Core\Test-ModuleManifest : The module manifest 'J:\Builds\
Jenkins\PROJECT_2456764.0\Applications\ALM\PSModules\MyCompany.Build\MyCompany.B
uild.psd1' could not be processed because it is not a valid Windows PowerShell
restricted language file. Remove the elements that are not permitted by the
restricted language:
At J:\Builds\Jenkins\PROJECT_2456764.0\Applications\ALM\PSModules\MyCompany.Bui
ld\MyCompany.Build.psd1:13 char:9
+ GUID = 'ccaa548f-8194-4cfa-a659-260f6ddc556b'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Unexpected token 'ccaa548f-8194-4cfa-a659-260f6ddc556b'
# Author of this module
Author = 'MyCompany'
# Company or vendor of this module
CompanyName = 'MyCompany' in expression or statement.
At J:\Builds\Jenkins\PROJECT_2456764.0\Applications\ALM\PSModules\MyCompany.Bui
ld\MyCompany.Build.psd1:13 char:9
+ GUID = 'ccaa548f-8194-4cfa-a659-260f6ddc556b'
+ ~
The hash literal was incomplete.
At J:\Builds\Jenkins\PROJECT_2456764.0\Applications\ALM\PSModules\MyCompany.Bui
ld\MyCompany.Build.psd1:19 char:25
+ CompanyName = 'MyCompany, Inc.'
+ ~
Missing argument in parameter list.
At J:\Builds\Jenkins\PROJECT_2456764.0\Applications\ALM\PSModules\MyCompany.Bui
ld\MyCompany.Build.psd1:118 char:1
+ }
+ ~
Unexpected token '}' in expression or statement.
At C:\Program Files
(x86)\WindowsPowerShell\Modules\PowerShellGet\1.0.0.1\PSModule.psm1:989 char:27
+ ... $module = Microsoft.PowerShell.Core\Test-ModuleManifest -Path $mani ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (J:\Builds\Jenki...Quip.Bui
ld.psd1:String) [Test-ModuleManifest], MissingMemberException
+ FullyQualifiedErrorId : Modules_InvalidManifest,Microsoft.PowerShell.Com
mands.TestModuleManifestCommand
Error that is caught
publish-module : The module 'DqCryptography' with version '1.0.2' cannot be published as the current version '1.0.2' is already available in the repository 'http://usas26:8624/nuget/PROJECTPowerShell/'.
At line:1 char:1
+ publish-module -Path DqCryptography -Repository PROJECTPowerShell - ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Publish-Module], InvalidOperationException
+ FullyQualifiedErrorId : ModuleVersionIsAlreadyAvailableInTheGallery,Publish-Module
Inside the try block add an error action to the Publish-Module
Publish-Module -Path .\$moduleName -Repository MyRepo -NuGetApiKey ghehdue -ErrorAction Stop

PowerShell module not dot-sourcing / importing functions as expected

Update 1:
Originally, I posted this with the title: "Scripts ignoring error handling in PowerShell module" as that is the current issue, however it seems more of a module issue, so I have renamed the title.
Update 2:
After a comment that made me question Azure cmdlets, I've tested with the most basic of scripts (added to the module) and the findings are the same, in that the error is not passed to the calling script, however, adding -errorVariable to Get-Service does return something (other than WriteErrorException) that I could probably harness in the handling of the error:
function Test-MyError($Variable)
{
Try
{
Get-Service -Name $variable -ErrorAction Stop -ErrorVariable bar
#Get-AzureRmSubscription -SubscriptionName $variable -ErrorAction Stop
}
Catch
{
Write-Error $error[0]
$bar
}
}
returns:
Test-MyError "Foo"
Test-MyError : Exception of type 'Microsoft.PowerShell.Commands.WriteErrorException' was thrown.
At line:3 char:1
+ Test-MyError "Foo"
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Test-MyError
The running command stopped because the preference variable "ErrorActionPreference" or common parameter is set to Stop: Cannot find any service with service name 'foo'.
However, if I run "Test-MyError" in ISE, then call the function, I get:
Test-MyError "Foo"
Test-MyError : Cannot find any service with service name 'Foo'.
At line:3 char:1
+ Test-MyError "Foo"
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Test-MyError
The running command stopped because the preference variable "ErrorActionPreference" or common parameter is set to Stop: Cannot find any service with service name 'Foo'.
So I am not sure what is happening when running "Test-MyError" in ISE and calling it, against it being dot-sourced in the PSM1 file and then calling it?
Do I now have to use -ErrorVariable and handle on that?
Original Question:
I have two functions in a module: Get-Subscription and Get-AllSubscriptions. Each function sits in its own PS1 file and the PSM1 file dot-sources them. The module seems fine as the module scripts are accessible using intelisense and the module loads without issue. I've used this structure in many modules and I haven't come across this problem before. (Although I wonder if MS have changed the way modules work in PS 5.1 as I have noticed using FunctionsToExport='x','y','Z' and Export-ModuleMember don't seem to behave the same way as they used to.)
Get-AllSubscriptions calls Get-Subscription.
If I am not logged into Azure, Get-Subscription should throw an error which is handled, prompting me to log in. This works as expected, if I call Get-Subscription from the Get-Subscription.ps1.
However, when I call Get-Subscription from the a new PS1 file, Get-AllSubscriptions or from the powershell console, it doesn't work. It iterates all the way through the do..until loop, without "handling" the errors as I would expect. On each iteration, it seems to throw a generic error:
Get-Subscription : Exception of type 'Microsoft.PowerShell.Commands.WriteErrorException' was thrown.
However, I do see the last error, Get-Subscription : Unable to find requested subscription after 3 login attempts.
If I execute Get-Subscription in ISE, then call Get-Subscription in a new PS1 file or from Get-AllSubscriptions, it works as expected, however, once I re-import the module (Import-Module AzureVnetTools -Force -Verbose), it goes back to the incorrect behaviour.
If I dot-source Get-Subscription, inside the caller script, it works, but why? This is what should happen with the module's PSM1.
Can anyone help me work out what I am doing wrong here?
(PS 5.1, Windows 7)
Get-Subscription:
function Get-Subscription
{
[cmdletbinding()]
Param
(
[string]$SubscriptionName,
[string]$UserName,
[string]$code
)
$c=1
Write-Verbose "Checking access to '$SubscriptionName' with user '$UserName'..."
Do
{
Write-Verbose "Attempt $c"
Try
{
$oSubscription = Get-AzureRmSubscription -SubscriptionName $SubscriptionName -ErrorAction Stop -WarningAction SilentlyContinue
Write-Verbose "Subscription found: $($oSubscription.SubscriptionName)."
}
Catch
{
if($error[0].Exception.Message -like "*Please verify that the subscription exists in this tenant*")
{
Write-Verbose "Cannot find subscription '$SubscriptionName' with provided credentials."
$account = Login-AzureRmAccount -Credential (Get-Credential -UserName $Username -Message "Subscription '$SubscriptionName' user' password:")
}
elseif($error[0].Exception.Message -like "*Run Login-AzureRmAccount to login*")
{
Write-Verbose "No logged in session found. Please log in."
$account = Login-AzureRmAccount -Credential (Get-Credential -UserName $Username -Message "Subscription '$SubscriptionName' user' password:")
}
else
{
Write-Error $error[0]
}
}
$c++
}
until(($oSubscription) -or ($c -eq 4))
if($c -eq 4)
{
Write-Error "Unable to find requested subscription after $($c-1) login attempts."
break
}
$oSubscription | Add-Member -MemberType NoteProperty -Name Code -Value $code
$oSubscription
}
Get-AllSubscriptions:
function Get-AllSubscriptions
{
[cmdletbinding()]
param
(
[string]$MasterSubscription,
[string]$MasterSubscriptionCode,
[string]$MasterSubscriptionUsername,
[string]$ChildSubscription,
[string]$ChildSubscriptionCode,
[string]$ChildSubscriptionUsername
)
Write-Verbose "Getting all subscriptions..."
$oAllSubscriptions = #()
$oMasterSubscription = Get-Subscription -SubscriptionName $MasterSubscription -UserName $MasterSubscriptionUsername -code $MasterSubscriptionCode -Verbose
$oChildSubscription = Get-Subscription -SubscriptionName $ChildSubscription -UserName $ChildSubscriptionUsername -code $ChildSubscriptionCode -Verbose
$oAllSubscriptions = ($oMasterSubscription,$oChildSubscription)
$oAllSubscriptions
}
Test:
$splat2 = #{
SubscriptionName = "SomeSubscription"
Code = "S02"
Username = "some.user#somewhere.com"
}
#Write-Output "Dot-source:"
#. "D:\Temp\PS.Modules\AzureVnetTools\functions\public\Get-Subscription.ps1"
Get-Subscription #splat2 -verbose
Output:
Get-Subscription #splat2 -verbose
VERBOSE: Checking access to 'SomeSubscription' with user 'some.user#somewhere.com'...
VERBOSE: Attempt 1
Get-Subscription : Exception of type 'Microsoft.PowerShell.Commands.WriteErrorException' was thrown.
At line:7 char:1
+ Get-Subscription #splat2 -verbose
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Get-Subscription
VERBOSE: Attempt 2
Get-Subscription : Exception of type 'Microsoft.PowerShell.Commands.WriteErrorException' was thrown.
At line:7 char:1
+ Get-Subscription #splat2 -verbose
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Get-Subscription
VERBOSE: Attempt 3
Get-Subscription : Exception of type 'Microsoft.PowerShell.Commands.WriteErrorException' was thrown.
At line:7 char:1
+ Get-Subscription #splat2 -verbose
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Get-Subscription
Get-Subscription : Unable to find requested subscription after 3 login attempts.
At line:7 char:1
+ Get-Subscription #splat2 -verbose
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Get-Subscription
AzureVnetTools.psm1
#Get public and private function definition files.
$Public = #( Get-ChildItem -Path $PSScriptRoot\Functions\Public\*.ps1 -ErrorAction SilentlyContinue )
$Private = #( Get-ChildItem -Path $PSScriptRoot\Functions\Private\*.ps1 -ErrorAction SilentlyContinue )
#Dot source the files
Foreach($import in #($Public + $Private))
{
#write-error $import.fullname
Try
{
#Write-Host "Dot-sourcing file: $($import.fullname)."
. $import.fullname
}
Catch
{
Write-Error -Message "Failed to import function $($import.fullname): $_"
}
}
Export-ModuleMember -Function $Public.Basename
AzureVnetTools.psd1 (Relevant section):
FunctionsToExport = '*'
-ErrorAction Stop -WarningAction SilentlyContinue
Is it a warning that's being thrown instead of an error?
So my specific problem was that I was relying on handling the error and doing something based on that. The problem was caused by the way PowerShell's Write-Error works (or not) as I learned from the reply here, given by #Alek.
It simply wasn't passing the actual error back to the calling script. As #Alex suggested, I replaced Write-Error with $PSCmdlet.WriteError(). Although this didn't totally work.
In the Catch{} block, I then changed $error[0] to $_ and the full error was returned to the calling script / function.
I went one further and wrote a reusable function, added to my module:
function Write-PsError
{
[cmdletbinding()]
Param
(
[Exception]$Message,
[Management.Automation.ErrorCategory]$ErrorCategory = "NotSpecified"
)
$arguments = #(
$Message
$null #errorid
[Management.Automation.ErrorCategory]::$ErrorCategory
$null
)
$ErrorRecord = New-Object -TypeName "Management.Automation.ErrorRecord" -ArgumentList $arguments
$PSCmdlet.WriteError($ErrorRecord)
}
Which seems to be working well at the moment. I especially like the way intellisense picks up all the ErrorCategories. Not sure what or how ISE (PS 5.1 / Win 7) does that. I thought I was going to have to add my own dynamic parameter.
HTH.