Created
March 15, 2021 20:09
-
-
Save Smalls1652/93badf4256bf5ab4c92ee5384cb200a7 to your computer and use it in GitHub Desktop.
Download Windows Admin Center through PowerShell
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<#PSScriptInfo | |
.VERSION 2021.03.00 | |
.GUID 0bbe0f49-d3c4-4479-993f-0b7f824f9ace | |
.AUTHOR Tim Small | |
.COMPANYNAME Smalls.Online | |
.COPYRIGHT 2021 | |
.TAGS | |
.LICENSEURI | |
.PROJECTURI | |
.ICONURI | |
.EXTERNALMODULEDEPENDENCIES | |
.REQUIREDSCRIPTS | |
.EXTERNALSCRIPTDEPENDENCIES | |
.RELEASENOTES | |
.PRIVATEDATA | |
#> | |
<# | |
.DESCRIPTION | |
Download Windows Admin Center through PowerShell. | |
#> | |
[CmdletBinding()] | |
param( | |
[Parameter(Position = 0, Mandatory)] | |
[ValidateNotNullOrEmpty()] | |
[string]$OutputDirectory | |
) | |
#Resolve the output directory provided and throw a terminating error if it can't be resolved. | |
$outputResolvedPath = (Resolve-Path -Path $OutputDirectory -ErrorAction "Stop").Path | |
#Define the generic 'aka.ms' URL for Windows Admin Center. | |
$wacGenericDownloadUrl = "https://aka.ms/WACDownload" | |
Write-Verbose "Getting the redirect URL from '$($wacGenericDownloadUrl)'." | |
#Need to create a HttpClient object with a 'ClientHandler' option for not allowing auto-redirect. This is to prevent the HttpClient from automatically resolving to the redirect-uri from the HTTP response. | |
$redirectHttpClient = [System.Net.Http.HttpClient]::new( | |
[System.Net.Http.HttpClientHandler]@{ | |
"AllowAutoRedirect" = $false | |
}, | |
$true | |
) | |
$redirectHttpClient.DefaultRequestHeaders.ConnectionClose = $true | |
#Send a HttpRequestMessage for the generic download URL, so we can grab what the redirect-uri is. | |
$redirectHttpReqMsg = [System.Net.Http.HttpRequestMessage]::new( | |
[System.Net.Http.HttpMethod]::Get, | |
$wacGenericDownloadUrl | |
) | |
$redirectHttpRsp = $redirectHttpClient.Send($redirectHttpReqMsg) | |
#Test to see if the 'Location' property exists in the header and that the StatusCode is set to 'Moved'. | |
$redirectLocation = $null | |
switch (($redirectHttpRsp.Headers.Contains("Location")) -and ($redirectHttpRsp.StatusCode -eq [System.Net.HttpStatusCode]::Moved)) { | |
$false { | |
$PSCmdlet.ThrowTerminatingError( | |
[System.Management.Automation.ErrorRecord]::new( | |
[System.Exception]::new("The response was returned with either the header not containing the 'Location' property or the 'StatusCode' was not set to 'Moved'. See the target object in the error record."), | |
"FailedToParseHttpHeaders", | |
[System.Management.Automation.ErrorCategory]::InvalidData, | |
$redirectHttpRsp | |
) | |
) | |
} | |
Default { | |
$redirectLocation = $redirectHttpRsp.Headers.Location.ToString() | |
break | |
} | |
} | |
$redirectHttpClient.Dispose() #Dispose the HttpClient | |
Write-Verbose "Redirected URL is '$($redirectLocation)'." | |
#Perform a regex on the URL that we would have been redirected to. This is to get the filename automatically. | |
$redirectRegex = [System.Text.RegularExpressions.Regex]::new( | |
"(?>https|http):\/\/download\.microsoft\.com[a-zA-Z0-9\/-]+\/(?'fileName'WindowsAdminCenter\d{1,4}\.msi)" | |
) | |
#Test to make sure the regex match will be successful. | |
switch ($redirectRegex.IsMatch($redirectLocation)) { | |
$false { | |
$PSCmdlet.ThrowTerminatingError( | |
[System.Management.Automation.ErrorRecord]::new( | |
[System.Exception]::new("The input URL, '$($redirectLocation)' failed the regex match."), | |
"FailedToGetFileNameFromUrl", | |
[System.Management.Automation.ErrorCategory]::ParserError, | |
$redirectLocation | |
) | |
) | |
} | |
} | |
#Run the match and get the matched string. | |
$redirectRegexMatch = $redirectRegex.Match($redirectLocation) | |
$downloadFileName = $redirectRegexMatch.Groups.Item('fileName').Value | |
#Join the path of the output directory and the file name it should be. | |
$downloadPath = Join-Path -Path $outputResolvedPath -ChildPath $downloadFileName | |
Write-Verbose "File name will be '$($downloadFileName)' and will be saved to '$($outputResolvedPath)'." | |
#Check to see if the file already exists and if the file, does prompt for overwrite. | |
Write-Verbose "Testing to see if the file already exists in '$($outputResolvedPath)'." | |
switch (Test-Path -Path $downloadPath) { | |
$true { | |
$overwriteFilePrompt = $PSCmdlet.ShouldContinue("File already exists", "Do you want to overwrite '$($downloadPath)'?") | |
switch ($overwriteFilePrompt) { | |
$false { | |
$PSCmdlet.ThrowTerminatingError( | |
[System.Management.Automation.ErrorRecord]::new( | |
[System.Exception]::new("File already exists"), | |
"FileAlreadyExists", | |
[System.Management.Automation.ErrorCategory]::ResourceExists, | |
$downloadPath | |
) | |
) | |
} | |
Default { | |
Remove-Item -Path $downloadPath -Force | |
break | |
} | |
} | |
} | |
} | |
#Create an HttpClient for the download | |
$downloadHttpClient = [System.Net.Http.HttpClient]::new() | |
$downloadHttpReqMsg = [System.Net.Http.HttpRequestMessage]::new( | |
[System.Net.Http.HttpMethod]::Get, | |
$redirectLocation | |
) | |
#Download the file. | |
Write-Verbose "Downloading file." | |
$downloadHttpRsp = $downloadHttpClient.Send($downloadHttpReqMsg) | |
$installFileByteArray = $downloadHttpRsp.Content.ReadAsByteArrayAsync().GetAwaiter().GetResult() | |
$downloadHttpClient.Dispose() #Dispose the HTTP client | |
$null = [System.IO.File]::WriteAllBytes($downloadPath, $installFileByteArray) #Write the byte array to the output path | |
$downloadedFile = Get-Item -Path $downloadPath | |
return $downloadedFile |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment