Powershell sanity check please. (Solved)
Can some kind person check if what follows is my poor coding or a bug, oddity, or whatever.
Code:
$URL = 'https://onegetcdn.azureedge.net/providers/providers.masterList.feed.swidtag'
$Online = Invoke-WebRequest -UseBasicParsing -Uri $URL
That, unless I've missed something, should be an xml document however powershell doesn't seem to treating as such..
Code:
$Online.Content | Get-Member
Doesn't return any objects from the xml document and..
Code:
[xml]$Online.Content
Says it "Cannot convert value "<?xml version="1.0" encoding="utf-8"?>" and "The specified node cannot be inserted as the valid child of this node, because the specified node is the wrong type."
I think it's something to do with either the formatting of the xml document or how Invoke-WebRequest/Invoke-RestMethod are decoding it because if i use "-outfile" and read it back in with "get-content" it works as you'd expect an xml file to work.
I've read some stuff about Invoke-WebRequest/Invoke-RestMethod screwing up BOM but I'm not entirely sure what, or how to spot, a BOM so can't tell if the above xml at the url is the problem or if it's my lack of powershell experience.
If it matters I'm currently parsing the xml document using this and while it works being able to use powershell's built in xml parsing would be a lot cleaner.
Code:
$URL = 'https://onegetcdn.azureedge.net/providers/providers.masterList.feed.swidtag'
$Online = Invoke-WebRequest -UseBasicParsing -Uri $URL
$Local = Get-ChildItem "$PathToScript\Files\Installers\Powershell\nuget" -Recurse -File
$OnlineVersion = $Online.Content | Select-String -Pattern 'https.*swidtag' | ForEach-Object { $_.Matches.Value }
if (($OnlineVersion -replace '\D') -gt ($Local.VersionInfo.FileVersion -replace '\D')) {
$Download = (Invoke-WebRequest -UseBasicParsing -Uri "$OnlineVersion").Content | Select-String -Pattern 'https.*\d.dll' | ForEach-Object { $_.Matches.Value }
$NewVersion = $Download | Select-String -Pattern '\d.+([\d]{1,3})' | ForEach-Object { $_.Matches.Value }
New-Item "$PathToScript\Files\Installers\Powershell\nuget\$NewVersion" -ItemType 'Directory' -Force | Out-Null
Invoke-WebRequest "$Download" -OutFile "$PathToScript\Files\Installers\Powershell\nuget\$NewVersion\Microsoft.PackageManagement.NuGetProvider.dll"
Remove-Item $Local.DirectoryName -Recurse -Force -EA 'SilentlyContinue'
}
Re: Powershell sanity check please. (Solved)
Just updating in case anyone comes across this.
I couldn't workout why Invoke-WebRequest/Invoke-RestMethod had problems parsing the swidtag as everything indicates it's a correctly formatted XML file so in the end i used the .net webclient, not sure if it makes for cleaner code but if anyone wants a laugh at how awful my coding is I'll leave what i ended up with bellow for people to pick holes in. :)
Code:
$URL = 'https://onegetcdn.azureedge.net/providers/providers.masterList.feed.swidtag'
[xml]$XML = (New-Object 'Net.WebClient').DownloadString($URL)
$Local = Get-ChildItem "$PathToScript\Files\Installers\Powershell\nuget" -Recurse -File
$Online = $XML.SoftwareIdentity.Link | Where-Object { ($_.rel -EQ 'package') -and ($_.name -eq 'nuget') }
if (([version]$Online.version) -gt ([version]$Local.VersionInfo.FileVersion)) {
$Download = [xml]$XML = (New-Object 'Net.WebClient').DownloadString($Online.href)
New-Item "$PathToScript\Files\Installers\Powershell\nuget\$($Online.version)" -ItemType 'Directory' -Force | Out-Null
Invoke-WebRequest "$Download" -OutFile "$PathToScript\Files\Installers\Powershell\nuget\$($Online.version)\Microsoft.PackageManagement.NuGetProvider.dll"
Remove-Item $Local.DirectoryName -Recurse -Force -EA 'SilentlyContinue'
}
Re: Powershell sanity check please. (Solved)
Couple of things. $Online.Content.GetType() returns System.String, not XmlDocument.
The document itself appears to have been created using a Windows editor and has the "magic" 3-byte Byte Order Mark (BOM) as the first 3 bytes, which according to the Wiki page for UTF is absolutely not recommended with UTF-8 encoding.
When you dump $Online.Content in your Powershell console window the first char is a space. Additionally, [int]$Online.Content[0] returns 65279, which is just the result of *interpreting* the BOM as the first Unicode character, instead of processing the BOM as metadata.
Anyway, long story short, [xml]$Online.Content.Substring(1) works - it ignores the first returned char. This is probably not a good idea tho.
Instead, [xml]$Online.Content.Substring($Online.Content.IndexOf('<')) is probably a better idea, and should keep working if the BOM disappears from the file in future.
This works just after your Invoke-WebRequest call.
Is that the best way to do it? Probably not. I just thought I'd post why it wasn't working for you :) There are a billion ways to do everything and every day you learn a better way to do x,y,z :p