1

I'm creating a log of attempted posts to an API. The API key is stored in a simple hash table and passed via Invoke-WebRequest:

$headers = @{ 'x-api-key' = 'ABC123DEF456GHI789' }
Try {
   [Net.ServicePointManager]::SecurityProtocol = 'tls12, tls11'
   $apiResponse = Invoke-WebRequest -Uri $url -Method $method -Headers $headers -Body $body
   $status            = $apiResponse.StatusCode
   $statusDescription = $apiResponse.StatusDescription
} Catch {
   $status            = $_.Exception.Response.StatusCode.value__
   $statusDescription = $_.Exception.Response.StatusDescription
}

I want to obscure the header key in the log, so I created and modified a new variable.

$obscured = $headers | ConvertTo-Json -depth 100 | ConvertFrom-Json
$obscured.'x-api-key' = $obscured.'x-api-key'.Substring(0,2) + '...' + $obscured.'x-api-key'.Substring($obscured.'x-api-key'.Length-2,2)

$logresults += [PSCustomObject]@{ 
   status            = $status
   statusDescription = $statusDescription 
   url               = $url
   method            = $method
   header            = $obscured 
   body              = ConvertFrom-JSON $body
}

I want to retain the header's structure as a key/value pair in the log. The extra steps prepping a new variable seem wasteful. Does PowerShell have a way to change the header key value upon assignment to the PSCustomObject?

Tony
  • 2,658
  • 2
  • 31
  • 46

1 Answers1

0

AFAIK, there is no easy way to obscure strings (or objects) in PowerShell or even .Net, see my related purpose: #16921 Add [HiddenString] Class. The only thing that exists is the gone crazy SecureString Class with difficult methodes to convert from a string and reveal string (as that is not secure). Besides, the SecureString might get obsolete (as it appears less secure than intended) and possibly replaced by a shrouded buffer which is even more difficult to use for obscuring information (if even possible in PowerShell).

Anyways, in the HiddenString idea you might do something like this:

$ApiKey = [HiddenString](Read-Host -AsSecureString 'Enter Api key:')

See also: How to encrypt/hide ClearText password in PowerShell Transcript

$Headers = @{
    'Accept'      = 'application/json'
    'X-My-Header' = 'Hello World'
    'x-api-key'   = $ApiKey
}

$apiResponse = Invoke-WebRequest -Uri $url -Method $method -Headers $($Headers.'x-api-key' = $ApiKey.Reveal(); $Headers) -Body $body

$logresults += [PSCustomObject]@{ # Avoid +=, see: https://stackoverflow.com/a/60708579/1701026
   status            = $status
   statusDescription = $statusDescription 
   url               = $url
   method            = $method
   header            = $Headers
   body              = ConvertFrom-JSON $body
}
iRon
  • 20,463
  • 10
  • 53
  • 79
  • I'm okay with the obscuring scheme that I chose. My question was more of simplifying the assignment of the hash value to the PSCustomObject. Like, can I change an inner value on the fly as opposed to having to create the interim replica and modifying that first. – Tony Jul 27 '22 at 15:18
  • I don't think there is a solution that works on the fly as you will always have to either: **a) reveal the headers/apikey for the webrequest** or **b) hide the headers/apikey for logging**. There is no way for a program or class to determine the difference. You might only make it easier by e.g. creating a function to either hide or reveal it (where -I think- actively revealing it from a hidden state is recommend to prevent accidentally showing it). – iRon Jul 27 '22 at 15:43