Powershell error output supression (again) - error-handling

I know this has been asked more than once before - because I've searched and read them all!..
Despite that, I am fighting a particularly obstinate powershell error that seemingly just will not let me suppress outputting great wodges of red to the screen. I'm doing a simple connection to the AzureAD module with this one-liner...
Connect-AzureAD -Credential $Credential
Note that I work in the Azure tenants of many different customers, some enforce 2FA, some do not. I'm writing a bunch of helper functions to ease the day-to-day grind of logging on and off many times to different tenants...
I know that cmdlet will fail when attempting to connect to a 2FA-enforced tenant... I expect it, and I want to trap it (silently) and handle that error myself. most of which I can do, but its the 'silently' bit that is particularly troublesome. I've tried every possible method of suppressing output that I know about (mostly from the other articles on here!).
With no countermeasures taken at all, that cmdlet generates 6 (six!) error events, all of which show onscreen. Using any of the supression methods I can think of, I can suppress 5 of those, but no matter what I try, one error always still appears onscreen... I have tried:
Connect-AzureAD -Credential $Credential *> .errors.txt
Connect-AzureAD -Credential $Credential *>&1 > .errors.txt
Connect-AzureAD -Credential $Credential *>&1 | out-null
Connect-AzureAD -Credential $Credential 2>&1 | out-null
Connect-AzureAD -Credential $Credential *>$null
$void=Connect-AzureAD -Credential $Credential -ErrorAction silentlycontinue
$void=Connect-AzureAD -Credential $Credential
Connect-AzureAD -Credential $Credential >$null
Connect-AzureAD -Credential $Credential|out-null
[void](Connect-AzureAD -Credential $Credential)
So far, absolutely nothing works to completely suppress all of the error output, - I always get that last 1 error ruining my tidy screen output.
I've also checked if the Connect-AzureAD cmdlet has any options such as -quiet or -silent etc. - it does not..
FYI, the actual error thrown is:
Connect-AzureAD : One or more errors occurred.: AADSTS50076: Due to a configuration change made by
your administrator, or because you moved to a new location, you
must use multi-factor authentication to access '00000002-0000-0000-c000-000000000000'.
Trace ID: 73e00fc9-6e7b-4210-8aa6-285b04692800
Correlation ID: 1b9e2d49-1ed6-4f1e-8ce9-65761a15edd9
Timestamp: 2020-02-14 16:12:10Z
At line:1 char:1
+ Connect-AzureAD -Credential $Credential *> .errors.txt
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Connect-AzureAD], AadAuthenticationFailedException
+ FullyQualifiedErrorId : Microsoft.Open.Azure.AD.CommonLibrary.AadAuthenticationFailedException,Microsoft.Open.Azure.AD.CommonLibrary.ConnectAzureAD
Does anyone have any ideas for a nuclear strength option to completely suppress absolutely all output from errors? My catch block does work to trap the [Microsoft.Open.Azure.AD.CommonLibrary.AadAuthenticationFailedException] named exception, so I can deal with the error just fine, but I really want to not have that splodge of red error text 'corrupting' my output.
TIA!
Paul G.

I tend to wrap most AzureAD code with try{}catch{}. A quick test seems to work for your case:
try {
Connect-AzureAD -ErrorAction Stop
} catch {
Write-Error -Message "Login cancelled or something..."
}
Hope you find this useful.

Related

Create keyvault secret - Operation returned an invalid status code 'Conflict'

I want to create multiple secrets in keyvault. Assign dynamic values of Blobstorage account, Batch account.
I tried below code to create secrets:
Function CreateKeyvaultSecrets
{
Param
(
[Parameter(Mandatory=$true, Position=0)]
[string] $keyvaultName,
[Parameter(Mandatory=$true, Position=1)]
[string] $blobStorageAccountName,
[Parameter(Mandatory=$true, Position=2)]
[string] $batchaccountName,
[Parameter(Mandatory=$true, Position=3)]
[string] $logRgName
)
#Get Storagekey
$blobStorageKeyObject = (Get-AzStorageAccountKey -ResourceGroupName $logRgName -AccountName $blobStorageAccountName)| Where-Object {$_.KeyName -eq "key1"}
$blobStorageKey = $blobStorageKeyObject.Value
$blobStorageConnectionString = "DefaultEndpointsProtocol=https;AccountName=$blobStorageAccountName;AccountKey=$blobStorageKey;EndpointSuffix=core.windows.net"
#Create blobstorage key secret
$blobSecretkey = ConvertTo-SecureString -String $blobStorageKey -AsPlainText -Force
Set-AzKeyVaultSecret -VaultName $keyvaultName -Name 'blobstorageaccesskey' -SecretValue $blobSecretkey
#Create blobstorage connectionstring key secret
$blobconnectionstringSecret = ConvertTo-SecureString -String $blobStorageConnectionString -AsPlainText -Force
Set-AzKeyVaultSecret -VaultName $keyvaultName -Name 'blobstorageconnectionstring' -SecretValue $blobconnectionstringSecret
Write-host "Blob Storage Account connection string added to Keyvault secret"
}
CreateKeyvaultSecrets 'kvtevalmock' 'steval' 'abtaeval' 'rg-eval'
I am trying to execute above code from Azure DevOps Powershell task. Azure powershell version is 5.
Secrets are not getting creating. Below error is thrown:
WARNING: Upcoming breaking changes in the cmdlet 'Set-AzKeyVaultSecret' :
- The output type 'Microsoft.Azure.Commands.KeyVault.Models.PSKeyVaultSecret' is changing
- The following properties in the output type are being deprecated : 'SecretValueText'
- The change is expected to take effect from the version : '3.0.0'
Note : Go to https://aka.ms/azps-changewarnings for steps to suppress this breaking change warning, and other
information on breaking changes in Azure PowerShell.
##[error]Operation returned an invalid status code 'Conflict'
##[error]PowerShell exited with code '1'.
I test your script on my side, it works fine.
From the error message, looks your Az.KeyVault powershell module version is too old, my version is 3.4.0, try to update it with the command below.
Update-Module -Name Az.KeyVault -Force
After the update, close all the powershell sessions and open a new one to try again, it should work.

Remove-AzureRmSqlDatabase keeps asking me to run LoginAzureRmAccount

I have an Azure SQL database which I want to delete. The command should be:
Remove-AzureRmSqlDatabase -ResourceGroupName $dbResourceGroup -ServerName $dbServerName -DatabaseName $dbToDelete -Whatif -Force
The error I keep getting back is
Remove-AzureRmSqlDatabase : Run Login-AzureRmAccount to login.
I tried running Login-AzureRmAccount as myself, then as a service principal I use for unattended scripts, and nothing worked.
I am able to log into the Azure RM portal and delete databases. I am also able to run Invoke-SqlCmd against this database to query and manipulate data.
How can I make this work?
According to this error message, it seems that you have not login Azure whit the right subscription.
We can use this command to get the sql database's information, and check the subscription.
(Get-AzureRmSqlDatabase -DatabaseName jasontest1 -ServerName jasontest -ResourceGroupName jasontest).resourceid
Then we can find the subscription in the powershell output.
PS C:\Users> (Get-AzureRmSqlDatabase -DatabaseName jasontest1 -ServerName jasontest -ResourceGroupName jasontest).resourceid
/subscriptions/5384xxxx-xxxx-xxxx-xxxx-xxxxe29axxxx/resourceGroups/jasontest/providers/Microsoft.Sql/servers/jasontest/databases/jasontest1
To find which subscription, we can use this command Get-AzureRmSubscription to list it:
PS C:\Users> Get-AzureRmSubscription
Name : Visual Studio Ultimate with MSDN
Id : 5384xxxx-xxxx-xxxx-xxxx-xxxxe29axxxx
TenantId : 1fcfxxx-xxxx-xxxx-xxxx9-xxxx8bf8xxxx
State : Enabled
Also we can use this command to select the subscription:
Get-AzureRmSubscription -SubscriptionId 5384xxxx-xxxx-xxxx-xxx-xxxxe29axxxx
My Powershell Azure modules had dependency errors for something. To fix it I (at the behest of Microsoft tech support) ran:
PS C:\> Install-Module AzureRM -Force
This re-installed it and fixed the dependency problems.

The specified module 'WebAdministration' was not loaded (Windows 2003, IIS 6)

I am trying to run some IIS admin scripts on machine with -
OS - Windows 2003(with SP2)
IIS - V6.0
Powershell - V2
However when I run following commands, I get the error -
- Import-Module WebAdministration
**Error**:
Import-Module : The specified module 'WebAdministration' was not loaded because no valid module file was found in any module directory.
At line:1 char:14 + Import-Module <<<< WebAdministration
+ CategoryInfo : ResourceUnavailable: (WebAdministration:String) [Import-Module], FileNotFoundException
+ FullyQualifiedErrorId : Modules_ModuleNotFound,Microsoft.PowerShell.Commands.ImportModuleCommand
- Add-PSSnapIn WebAdministration
**Error:**
Add-PSSnapin : No snap-ins have been registered for Windows PowerShell version 2.
At line:1 char:13 + Add-PSSnapIn <<<< WebAdministration
+ CategoryInfo : InvalidArgument: (WebAdministration:String) [Add-PSSnapin], PSArgumentException
+ FullyQualifiedErrorId : AddPSSnapInRead,Microsoft.PowerShell.Commands.AddPSSnapinCommand
I checked which modules/snapin are available - here is the result -
Get-Module -ListAvailable
Result:
BitsTransfer
Get-PSSnapIn
Result:
Microsoft.PowerShell.Diagnostics
Microsoft.WSMan.Management
Microsoft.PowerShell.Core
Microsoft.PowerShell.Utility
Microsoft.PowerShell.Host
Microsoft.PowerShell.Management
Microsoft.PowerShell.Security
Please guide what shall I do to run IIS administration scripts.
Below link says Powershell SnapIn is not available for IIS 6.0:
http://forums.iis.net/p/1156851/1903821.aspx#1903821
WMI is the option to go with IIS 6.0 administration.
But WMI is not the option for me as soon we will be upgrading to IIS 7.5
In IIS6 on Windows 2k3 platform, I suggest you try accessing IIS via the old WMI provider ("Microsoftiisv2") or ADSI provider as both are accessible from the PowerShell.
Neither snapins nor WebAdministration module is available for IIS 6.0, so we can access IIS6 metabase from PowerShell using either
For IIS7.0, we can "import WebAdministration" module.
For example, I had to set the physical path for a virtual directory for IIS6, so I made use of a vbs script,iisvdir that comes along with IIS6 in c:/Windows/System32 .
Copying the code snippet
Function resetSiteLocation ($newPath)
{
Write-Host "List of Virtual directories for the site Test123 before reset :"
C:\WINDOWS\system32\iisvdir /query Test/Test123
Write-Host "About to reset site location"
C:\WINDOWS\system32\iisvdir /delete Test/Test123/Test1
C:\WINDOWS\system32\iisvdir /create Test/Test123 Test1 C:\projects\Test\Test123\Test1
C:\WINDOWS\system32\iisvdir /delete Test/Test123/Test2
C:\WINDOWS\system32\iisvdir /create Test/Test123 Test2 C:\projects\Test\Test123\Test2
Write-Host "Finished to reset site location"
Write-Host "List of Virtual directories for the site Test123 after reset :"
C:\WINDOWS\system32\iisvdir /query Test/Test123
}
Since you would be making a switch to higher version of IIS, you could put a switch in your code to determine the IIS version and take action as appropriate.
I did this:
Write-Host "Checking Installed IIS version:"
$iisVersion = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\InetStp";
Write-host IIS major version : $iisVersion.MajorVersion
Write-host IIS minor version : $iisVersion.MinorVersion
Write-Host "Finished the check."
## IIS inclusion module
## Neither snapins nor WebAdministration module is available for IIS 6.0, so we can access IIS6 metabase
## from PowerShell using either old WMI provider ("Microsoftiisv2") or ADSI provider as both are accessible from the PowerShell.
## For IIS7.0, we can import WebAdministration module
if (($iisVersion.MajorVersion -eq 7 ) -or ($iisVersion.MajorVersion -ge 7 ))
{
Write-host Detected IIS Major Version : $iisVersion.MajorVersion and Minor version : $iisVersion.MinorVersion. Hence importing WebAdministration module.
Import-Module WebAdministration;
Write-Host "About to reset app pool"
Restart-WebAppPool("Application")
Write-Host "Finished resetting app pool"
resetSiteLocation
Write-Host "About to reset site"
Restart-WebItem("IIS:\Sites\My application")
Write-Host "Finished to reset site"
}
elseif ($iisVersion.MajorVersion -eq 6)
{
Write-host IIS version 6 detected. Hence accessing IIS metabase using old WMI provider
##2. Reset App Pool
Write-Host "About to reset app pool"
Write-Host "Finished resetting app pool"
##3. Reset site location
resetSiteLocation
##4.Reset site
Write-Host "About to reset site"
Write-Host "Finished to reset site"
}
else
{
Write-host Detected IIS $iisVersion.MajorVersion
}
Let me know if it helps you.
Here is some good information on using the WMI interface with IIS 6:
http://network-nick.blogspot.com/2015/01/powershell-and-iis-6.html
He also points to the Microsoft documentation of cmdlets for this environment, here:
https://learn.microsoft.com/en-us/previous-versions/iis/6.0-sdk/ms525265(v=vs.90)
During the article he develops and explains the following PowerShell script for listing a server's web sites and their virtual directories. I actually tried this and it works.
$WebSiteID = Get-WmiObject -Namespace "root/MicrosoftIISv2" -Class IIsWebServer | Select-Object -ExpandProperty Name
ForEach ( $Site in $WebSiteID ) {
$WebSiteName = Get-WmiObject -Namespace "root/MicrosoftIISv2" -Class IIsWebServerSetting | Where-Object { $_.Name -like "$site" } `
| Select-Object -Expandproperty ServerComment
write-host "`r`n" $WebSiteName
$AppPath = Get-WmiObject -Namespace "root/MicrosoftIISv2" -Class IIsWebVirtualDirSetting | Where-Object { $_.Name -like "$site/*" } `
| select -expandproperty path
$AppPath = $AppPath | select-object -unique | sort-object
$AppPath
}

Powershell Version 2 Load DLL for use on persistent connection's invoke command scriptblock

Does anyone know how I can load a DLL without having it on each remote server I am using in a persistent connection and running the invoke-command cmdlet with?
I am using DotNetZip to backup folders on about 13 servers. Everything is working locally, but when it gets to a remote server (the first one in the array is the local server), it errors because it doesn't see the DLL on the remote server.
I execute this script on one server and it should zip up folders on each remote server:
foreach($i in $appServers) {
$sessionForI = New-PSSession -computername $i
Invoke-Command -Session $sessionForI -ScriptBlock {
if (!(Test-Path -path C:\\newDeploy)) {
New-Item C:\\newDeploy -type directory
}
[System.Reflection.Assembly]::LoadFrom("C:\\newDeploy\\Ionic.Zip.dll");
$directoryToZip = "C:\\Program Files (x86)\\SubDir\\$folder"
$zipfile = new-object Ionic.Zip.ZipFile
$e = $zipfile.AddSelectedFiles("name != '*.e2e'",$directoryToZip, "",1)
if (!(Test-Path -path C:\\newDeploy\\backup)) {
New-Item C:\\newDeploy\\backup -type directory
}
$zipfile.Save("C:\\newDeploy\\backup\\" + $folder+ ".zip")
$zipfile.Dispose()
}
remove-PSSession -session $sessionForI
}
Thank you .
-Jim
I'm pretty sure you are going to need to copy Ionic.Zip.dll to the remote machines to do this. You could try sharing it out from your lead system and using a UNC path to load it from the remote machines (i've never tried that... going to now...) :-)
Update - yep just confirmed you can pass a UNC path to [System.Reflection.Assembly]::LoadFrom.
Update 2 - While the assembly loaded, using it didn't work so well:
Exception calling "AddFile" with "1" argument(s): "Request for the permission of type 'System.Security.Permissions.File
IOPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed."
At line:1 char:11
+ $z.AddFile <<<< ("C:\AMCleanUp.log")
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
When I loaded a local copy of the the DLL the AddFile method worked fine. You're only option might be to copy this DLL to all your servers...
You can use a UNC path in the LoadFrom for the remote boxes, but I see that someone has had problem doing the same with DotNetZip:
http://social.technet.microsoft.com/Forums/en-US/winserverpowershell/thread/dd5dcae2-1ccc-4be2-b986-61c069102ffb/
I think your problems with accessing remote resources in an already remote session has to do with double-hop authentication. Check this link http://www.ravichaganti.com/blog/?p=1230

Removing self signed certificate from my store

Is there a way to remove/ uninstall a self signed certificate from my store using powershell ?
I tried
Remove-Item cert:\LocalMachine\My\$thumb
it did not work, I got an exception saying "Provider does not support this operation"
I also tried
certmgr.msc /del /n "MyTestServer" /s MY
it did not work either
How can I uninstall certificate from store ??
Thanks in advance
Jeez
This approach seems to apply to Powershell 2 only and thus it is outdated.
Remove-Item does not work with certificates because der cert-provider is readonly in powershell. Found that information here
$store = new-object system.security.cryptography.x509certificates.x509Store 'My','CurrentUser'
$store.Open('ReadWrite')
$certs = #(dir cert:\currentuser\my | ? { $_.Subject -like '*MyTestServer*' })
foreach ($cert in $certs) {$store.Remove($cert)}
$store.close()
I found the solution here in the comments. So it is untested.
Found this article because remove-item wasn't working.
This is not exactly 'true' powershell, but I use this method:
certutil -delstore my "5314bdfa0255be36e53e749d033"
You can get thumbprint via cert:\LocalMachine\my or through certutil. In my case, I have multiple certs with exact same name, so I like above method more because it gives me a specific target when I delete a cert.
With PS 3.0, if you want to remove by subjectName
Get-ChildItem -Path Cert:\CurrentUser\My | where { $_.subject -eq "CN=MysubjectName" } | Remove-Item
With PS 3.0 there is a more concise and idiomatic approach:
Remove-Item -Path cert:\LocalMachine\My\{Thumbprint} -DeleteKey
See TechNet for all the details.
This will work as well in powershell
To get the thumbpeint
dir cert:\localmachine\my
To delete the thumbprint
del cert:\localmachine\my\thumbprint
Realise this is an old thread, but since I'm looking at doing the same right now thought I'd post. I'm needing to remove from all cert stores by friendly name.
Realise this isn't the answer for OP but may help someone.
If that is required by anyone this works for me dir cert: -Recurse | Where-Object { $_.FriendlyName -like "*SOMENAME*" } | Remove-Item
You are set on wrong cert store
Use $cert = Get-ChildItem -Path "Cert:\CurrentUser\My\THUMBPRINT" instead of cert:\LocalMachine\My\$thumb you say that the certificates are your. So your certificates are stored in -Path "Cert:\CurrentUser\My\THUMBPRINT" CurrentUser = Your user account, and you don't need to change it to your account name.
br.