Friday 8 May 2020

Set-AzStorageBlobContent and Illegal characters in path

Occasionally I upload some content to an Azure Blob storage account for long term archival from a Windows 2016 server using a script (upload-azure.ps1) and the AZ PowerShell modules, specifically Set-AzStorageBlobContent.
When I last ran this 4 months ago, back in Jan 2020, it went fine. I got the error below a month or so ago and just used the web interface to upload instead. Today, when I have lots of content to upload it was time to get the script working. This is what was getting:

Set-AzStorageBlobContent : Failed to open file C:\Upload\Al.7z: Illegal characters in path..
At C:\Upload\upload-azure.ps1:95 char:13
+             Set-AzStorageBlobContent -File $FilePath -Container $cont ...
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : CloseError: (:) [Set-AzStorageBlobContent], TransferException
    + FullyQualifiedErrorId : TransferException,Microsoft.WindowsAzure.Commands.Storage.Blob.SetAzureBlobContentCommand
The relevant line 95 from the script is:

Set-AzStorageBlobContent -File $FilePath -Container $containerName -Context $storageAccount.Context -Blob $file.Name -Metadata $Metadata
I updated the Az.Storage PowerShell modules (see the fun and games here) to v1.14.0 and tried again. Same issue. However, it turns out there has been some path handling changes in .Net Framework that turned up on my server of recent. This article https://docs.microsoft.com/en-gb/archive/blogs/jeremykuhne/new-net-path-handling-sneak-peek hints to it. Checking the basics of path handling with this below points to something more in .Net than in the Az commands:

PS C:\Users\Al> [System.IO.Path]::GetFullPath("\\?\c:\pagefile.sys")
Exception calling "GetFullPath" with "1" argument(s): "Illegal characters in path."
At line:1 char:1
+ [System.IO.Path]::GetFullPath("\\?\c:\pagefile.sys")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ArgumentException
Then reading this again, https://github.com/Azure/azure-powershell/issues/8473, it now has a solution on it that easy to apply - thanks fimcle!

$registryPath = "HKLM:\SOFTWARE\Microsoft.NETFramework\AppContext"
New-Item -Path $registryPath
New-ItemProperty -Path $registryPath -Name "Switch.System.IO.UseLegacyPathHandling" -Value "false"
Run that and open a new PowerShell window and hazaah, I can now upload content to my Blob storage again.

Thursday 7 May 2020

Error "PowerShell Gallery is currently unavailable"

I was trying to update some Az modules on a Windows 2016 server (PowerShell version 5.1.14393.3471 for what it's worth) today to connect to some Azure storage and thought I'd run the normal Update-Module to keep things nice and fresh. However, this time it was failing with:

PS C:\Users\Al> Update-Module
Get-PSGalleryApiAvailability : PowerShell Gallery is currently unavailable.  Please try again later.
At C:\Program Files\WindowsPowerShell\Modules\PowerShellGet\1.0.0.1\PSModule.psm1:2038 char:13
+             Get-PSGalleryApiAvailability -Repository (Get-SourceName  ...
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (:) [Get-PSGalleryApiAvailability], InvalidOperationException
    + FullyQualifiedErrorId : PowerShellGalleryUnavailable,Get-PSGalleryApiAvailability
So running it with a debug gets me this (with some cruft removed):

PS C:\Users\Al>Update-Module -Debug
DEBUG: 00:00:47.3393273 Source 'https://www.powershellgallery.com/api/v2' is not one of the 'NuGet' provider.
...SNIP....
VERBOSE: An error occurred while sending the request.
VERBOSE: Retry downloading 'https://www.powershellgallery.com/api/v2' for '2' more times
VERBOSE: An error occurred while sending the request.
VERBOSE: Retry downloading 'https://www.powershellgallery.com/api/v2' for '1' more times
VERBOSE: An error occurred while sending the request.
VERBOSE: Retry downloading 'https://www.powershellgallery.com/api/v2' for '0' more times
WARNING: Unable to resolve package source 'https://www.powershellgallery.com/api/v2'.
...SNIP...
Interesting. Lets just try check the repository is good first:

PS C:\Users\Al> Get-PSRepository
WARNING: MSG:UnableToDownload «https://go.microsoft.com/fwlink/?LinkID=627338&clcid=0x409» «»
WARNING: Unable to download the list of available providers. Check your internet connection.

Name                      InstallationPolicy   SourceLocation
----                      ------------------   --------------
PSGallery                 Untrusted            https://www.powershellgallery.com/api/v2
OK. Well it looks good but that warning is funny. Looking at the firewall logs it showed successful connections to www.powershellgallery.com so it wasn't access out to the internet. Lets try and install the module again.

PS C:\Users\Al> Install-Module -Name Az
WARNING: Unable to resolve package source 'https://www.powershellgallery.com/api/v2'.
PackageManagement\Install-Package : No match was found for the specified search criteria and module name 'Az'. Try
Get-PSRepository to see all available registered module repositories.
At C:\Program Files\WindowsPowerShell\Modules\PowerShellGet\1.0.0.1\PSModule.psm1:1772 char:21
+ ...          $null = PackageManagement\Install-Package @PSBoundParameters
+                      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (Microsoft.Power....InstallPackage:InstallPackage) [Install-Package], Ex
   ception
    + FullyQualifiedErrorId : NoMatchFoundForCriteria,Microsoft.PowerShell.PackageManagement.Cmdlets.InstallPackage
Bother. At this point, having found three different error messages and being able to download the URL's in the warnings using IE, I looked into some Wireshark dumps and noticed that while the IE was using TLS1.2, this PowerShell was not and failing at the server side to connect properly. Time to enforce TLS1.2 in the PowerShell session with this command:

[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Rerun the Update-Module and it works. I'm not sure what I might have done to stop it working, perhaps a GPO or some such to set PowerShell to default to TLS1.1 or 1.0 or perhaps PowerShellGallery turned off TLS1.0 and 1.1 support (smart move). You can Google that one to find a better place to put that line so it sticks for each session.