Skip to content

Instantly share code, notes, and snippets.

@keyan1603
Created December 15, 2025 16:58
Show Gist options
  • Select an option

  • Save keyan1603/9e00c4dc77b88ad381d9a9c74e22f562 to your computer and use it in GitHub Desktop.

Select an option

Save keyan1603/9e00c4dc77b88ad381d9a9c74e22f562 to your computer and use it in GitHub Desktop.
Upload file to S3 bucket without AWS CLI module
# ============================================
# 1. Set your values here
# ============================================
$AccessKey = 'AKIAY…..'
$SecretKey = 'xxxx'
$Region = "xxx"
$BucketName = "bucketname"
$Prefix = "packages"
$LocalFile = 'C:\testfile.zip'
# ============================================
# 2. Build S3 URL & key
# ============================================
$fileName = [IO.Path]::GetFileName($LocalFile)
if ([string]::IsNullOrWhiteSpace($Prefix)) {
$ObjectKey = $fileName
} else {
$ObjectKey = ($Prefix.TrimEnd("/") + "/" + $fileName)
}
$AWSHost = "$BucketName.s3.$Region.amazonaws.com"
$Url = https://$AWSHost/$ObjectKey
# Read file into memory
$Body = [IO.File]::ReadAllBytes($LocalFile)
$sha256 = [System.Security.Cryptography.SHA256]::Create()
$hashBytes = $sha256.ComputeHash($Body)
$sha256.Dispose()
$payloadHashHex = ([System.BitConverter]::ToString($hashBytes)).Replace("-", "").ToLowerInvariant()
# ============================================
# 3. Build SigV4 Canonical Request
# ============================================
#optional - remove setting ServicePointManager if not required
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$head = Invoke-WebRequest -Method Get -Uri https://s3.amazonaws.com/ -UseBasicParsing
$serverDate = [DateTime]::Parse($head.Headers["Date"]).ToUniversalTime()
$amzDate = $serverDate.ToString("yyyyMMddTHHmmssZ")
$dateStamp = $serverDate.ToString("yyyyMMdd")
$Method = "PUT"
$CanonicalUri = "/" + $ObjectKey
$canonicalQueryString = ""
$CanonicalHeaders = "host:$AWSHost`n" + "x-amz-content-sha256:$payloadHashHex`n" + "x-amz-date:$amzDate`n"
$SignedHeaders = "host;x-amz-content-sha256;x-amz-date"
$PayloadHash = $payloadHashHex
$CanonicalRequest = @"
$Method
$CanonicalUri
$canonicalQueryString
$CanonicalHeaders
$SignedHeaders
$PayloadHash
"@
# SHA256 hash
$CanonicalRequestHash = [BitConverter]::ToString((New-Object Security.Cryptography.SHA256Managed).ComputeHash([Text.Encoding]::UTF8.GetBytes($CanonicalRequest))).Replace("-", "").ToLower()
# ============================================
# 4. String To Sign
# ============================================
$CredentialScope = "$dateStamp/$Region/s3/aws4_request"
$StringToSign = @"
AWS4-HMAC-SHA256
$amzDate
$CredentialScope
$CanonicalRequestHash
"@
# ============================================
# 5. Generate AWS Signature V4
# ============================================
function Hmac([byte[]]$Key, [string]$Data) {
$h = New-Object Security.Cryptography.HMACSHA256
$h.Key = $Key
return $h.ComputeHash([Text.Encoding]::UTF8.GetBytes($Data))
}
$kSecret = [Text.Encoding]::UTF8.GetBytes("AWS4$SecretKey")
$kDate = Hmac $kSecret $dateStamp
$kRegion = Hmac $kDate $Region
$kService = Hmac $kRegion "s3"
$kSigning = Hmac $kService "aws4_request"
$Signature = [BitConverter]::ToString((New-Object Security.Cryptography.HMACSHA256 -Property @{ Key = $kSigning }).ComputeHash([Text.Encoding]::UTF8.GetBytes($StringToSign))).Replace("-", "").ToLower()
# ============================================
# 6. Prepare headers
# ============================================
$Authorization = "AWS4-HMAC-SHA256 Credential=$AccessKey/$CredentialScope, SignedHeaders=$SignedHeaders, Signature=$Signature"
$Headers = @{
"x-amz-date" = $amzDate
"x-amz-content-sha256" = $payloadHashHex
"Authorization" = $Authorization
}
Write-Host "Uploading $LocalFile → s3://$BucketName/$ObjectKey"
# ============================================
# 7. Upload using raw HTTPS REST call
# ============================================
try {
$resp = Invoke-RestMethod -Uri $Url -Method PUT -Headers $Headers -Body $Body
Write-Host "Upload complete!"
$resp
}
catch {
Write-Warning "Upload failed: $($_.Exception.Message)"
if ($_.Exception.Response -and $_.Exception.Response.GetResponseStream()) {
$reader = New-Object IO.StreamReader ($_.Exception.Response.GetResponseStream())
$errorBody = $reader.ReadToEnd()
Write-Host "----- AWS Error Body -----"
Write-Host $errorBody
}
throw
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment