
Today I was asked a “HEEEELLLLPPP” question at the end of the day. I typically like those types of questions so I was fully engaged! As a result, I was quite activated for a couple of hours, so I decided to make a blog out of it directly!
Let me provide a little context. The help question was related to Dependency-Track. I won’t go into details on the tool itself but if you are interested I would start at the dependencytrack.org website. Back to the question, there was a working PostMan call but getting a PowerShell script to posting a BOM (Bill Of Material) through posting Form Data is not as simple as you would expect, so this is where we were stuck…
First, the easy part, getting a version of Dependency-Track running locally. This gist shows you that a few lines can get you started with a container to do just that. It is easy to configure and allows you to be up-and-running in no time.
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
docker pull owasp/dependency–track | |
docker volume create —name dependency–track | |
docker run –d –m 8192m –p 8080:8080 —name dependency–track –v dependency–track:/data owasp/dependency–track |
While we had a working PostMan Call, we could make use of the PostMan code examples, combined with lot’s of extra search result tabs in my browser, as well as good discussion and screen sharing session we came to the following working script.
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
try { | |
Set-Location $PSScriptRoot | |
$ProjectGuid = "d78bc750-d6db-4805-9836-5d77075ec37a" | |
$ApiKey = "6Ue2f8uVfRiVGpdowjWfF3yW02ryA7Uc" | |
$Uri = "http://localhost:8080/api/v1/bom" | |
$FileName = "bom.xml" | |
$ContentType = "multipart/form-data" | |
$xml = Get-Content (Join-Path $PSScriptRoot $FileName) –Raw | |
$httpClientHandler = [System.Net.Http.HttpClientHandler]::new() | |
$httpClient = [System.Net.Http.Httpclient]::new($httpClientHandler) | |
$multipartContent = [System.Net.Http.MultipartFormDataContent]::new() | |
$projectHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data") | |
$projectHeader.Name = "project" | |
$projectContent = [System.Net.Http.StringContent]::new($ProjectGuid) | |
$projectContent.Headers.ContentDisposition = $projectHeader | |
$multipartContent.Add($projectContent) | |
$bomHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data") | |
$bomHeader.Name = "bom" | |
$bomContent = [System.Net.Http.StringContent]::new($xml) | |
$bomContent.Headers.ContentDisposition = $bomHeader | |
$multipartContent.Add($bomContent) | |
$httpClient.DefaultRequestHeaders.Add("X-API-Key", $ApiKey); | |
$response = $httpClient.PostAsync($Uri, $multipartContent).Result | |
$response.Content.ReadAsStringAsync().Result | |
} | |
catch { | |
Write-Host $_ | |
} | |
finally { | |
if ($null -ne $httpClient) { | |
$httpClient.Dispose() | |
} | |
if ($null -ne $response) { | |
$response.Dispose() | |
} | |
} |
There is no magic but creating the objects to be able to properly post MultipartFormDataContent is not something I do on a daily basis. While we were happy with the working solution, I was not completely satisfied with this result. There must be other ways of doing this. One another way I found is using another API call that also allows larger content. That will come in handy when parsing a combination of BOM files!
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
try { | |
$xml = Get-Content (Join-Path $PSScriptRoot ".\bom.xml") –Raw | |
$ProjectGuid = "d78bc750-d6db-4805-9836-5d77075ec37a" | |
$ApiKey = "6Ue2f8uVfRiVGpdowjWfF3yW02ryA7Uc" | |
$Uri = "http://localhost:8080" | |
$Body = ([PSCustomObject] @{ | |
project = $ProjectGuid | |
bom = ([Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($xml))) | |
} | ConvertTo-Json) | |
$Header = @{ 'X-API-Key' = $ApiKey } | |
Invoke-RestMethod –Method Put –Uri "$Uri/api/v1/bom" –Headers $Header –ContentType "application/json" –Body $Body | |
} | |
catch { | |
Write-Host $_ | |
} |
This file is something like you would expect in the first place. Much more condensed and lot less typing and types flying around. Also working with the Invoke-RestMethod is a lot more common. Great improvement found during the troubleshooting! Convenient is that this also works in PowerShell Core!
I hope this post helps you when you are in search of posting some BOM files to Dependency-Track with PowerShell!