Skip to main content

Search OfficeIMO

Enter a topic, API type, or PowerShell command.

Documentation Search all OfficeIMO/

Compare supplier quotes without retyping an HTML table

Edit on GitHub

Read supplier offers with PSParseHTML, compare price and delivery, and create an editable Word review, PDF and numeric Excel workbook with PSWriteOffice.

You have a supplier price list in an HTML page and need to buy equipment for a team. Copying the table into Excel is easy enough once. Doing it again when a quote changes, fixing prices that became text, and copying the comparison into a Word document is where the time goes.

PSParseHTML can read the table directly. PSWriteOffice can use those rows to create an Excel workbook for the calculations and a Word/PDF review for the purchasing decision. Let's build that comparison, keeping both price and delivery time visible.

Supplier review showing the offers and questions to resolve before purchasing

The example produces an editable Word review, a PDF, and a workbook with numeric prices. Run the blocks below in the same PowerShell session to create them yourself.

Read the offers once

Install the two modules once if needed:

Install-Module PSParseHTML, PSWriteOffice -Scope CurrentUser

Here's a small example price list. The names and prices are illustrative; use the HTML from your supplier's export when applying this to a real purchase. Giving the table an ID lets us select the offers without accidentally reading a navigation or layout table elsewhere on the page.

Import-Module PSParseHTML
Import-Module PSWriteOffice
$ErrorActionPreference = 'Stop'

$html = @'
<table id="offers">
  <tr><th>Item</th><th>Supplier</th><th>UnitPriceUsd</th><th>LeadDays</th></tr>
  <tr><td>USB-C dock</td><td>Northwind</td><td>89.50</td><td>4</td></tr>
  <tr><td>USB-C dock</td><td>Contoso</td><td>92.00</td><td>2</td></tr>
  <tr><td>27-inch monitor</td><td>Northwind</td><td>215.00</td><td>5</td></tr>
  <tr><td>27-inch monitor</td><td>Contoso</td><td>208.00</td><td>7</td></tr>
</table>
'@
$tables = @(ConvertFrom-HtmlTable -Content $html -TableId offers -IncludeMetadata)
if ($tables.Count -ne 1 -or @($tables[0].Data).Count -eq 0) {
    throw 'Expected one nonempty offers table.'
}

For a saved page, replace the ConvertFrom-HtmlTable call with ConvertFrom-HtmlTable -Path ./SupplierOffers.html -TableId offers -IncludeMetadata. Keep the four column names above, or map your supplier's headings to those names before the next step.

Make the prices usable in Excel

HTML cells contain text. Convert prices and lead times before creating the documents so that Excel can calculate with them. This price list uses USD, a decimal point, and no thousands separators. Reject a value you can't interpret instead of quietly turning it into zero.

$culture = [Globalization.CultureInfo]::InvariantCulture
$priceFormat = '0.00##########################'
$offers = @($tables[0].Data | ForEach-Object {
    if ([string]::IsNullOrWhiteSpace($_.Item) -or [string]::IsNullOrWhiteSpace($_.Supplier)) {
        throw 'An offer needs an item and supplier.'
    }
    $text = [string] $_.UnitPriceUsd
    $parts = $text.Split('.')
    $fraction = if ($parts.Count -eq 2) { $parts[1].TrimEnd('0') } else { '' }
    $digits = ($parts[0].TrimStart('0') + $fraction).TrimStart('0')
    [decimal] $price = 0
    if ($digits.Length -gt 15 -or $fraction.Length -gt 28 -or
        -not [decimal]::TryParse($text, [Globalization.NumberStyles]::AllowDecimalPoint,
            $culture, [ref] $price)) {
        throw "Unsupported USD price: $text"
    }
    $days = [int]::Parse($_.LeadDays, $culture)
    if ($price -lt 0 -or $days -lt 0) { throw 'Price and lead time must be nonnegative.' }
    [pscustomobject]@{
        Item = [string] $_.Item
        Supplier = [string] $_.Supplier
        UnitPriceUsd = $price
        LeadDays = $days
    }
})
$offers | Sort-Object Item, UnitPriceUsd | Format-Table

Now the comparison has something useful to say. Northwind's dock is $2.50 cheaper, but Contoso's arrives two days sooner. Contoso's monitor saves $7, but adds two days to the lead time. A cheapest-price sort alone would miss that tradeoff. Freight, tax, stock and the date you actually need the equipment still belong in the decision.

The precision check keeps the Word text and numeric Excel prices aligned, including sub-cent quotes. Excel numbers support at most 15 significant decimal digits; this example also rejects fractional precision beyond .NET decimal rather than allowing a tiny price to round to zero.

Create a comparison the buyer can edit

The document has a clear title, one compact comparison table and a place to record what needs checking. Format the price for the Word table while leaving the original $offers numeric for Excel.

$output = New-Item -ItemType Directory -Path ./Output/SupplierReview -Force
$docx = Join-Path $output.FullName 'SupplierReview.docx'
$pdf = Join-Path $output.FullName 'SupplierReview.pdf'
$xlsx = Join-Path $output.FullName 'SupplierOffers.xlsx'
$reviewRows = $offers | Select-Object Item, Supplier,
    @{Name='USD per unit'; Expression={$_.UnitPriceUsd.ToString($priceFormat, $culture)}},
    @{Name='Lead days'; Expression={$_.LeadDays}}

New-OfficeWord -Path $docx {
    WordHeader { WordParagraph -Text 'PROCUREMENT / OFFER REVIEW' }
    WordFooter { WordPageNumber -IncludeTotalPages }
    WordParagraph {
        WordParagraphStyle -SpacingAfterPoints 12 -KeepWithNext $true
        WordText 'Supplier offer review' -Bold -FontSize 26 -Color '17365D'
    }
    WordParagraph {
        WordParagraphStyle -SpacingAfterPoints 10
        WordText "$($offers.Count) offers to compare" -Bold -FontSize 16 -Color '166534'
    }
    WordParagraph -Text 'Compare unit price and delivery together. Freight and tax are excluded.'
    WordParagraph {
        WordParagraphStyle -SpacingBeforePoints 16 -SpacingAfterPoints 8 -KeepWithNext $true
        WordText 'Offers received' -Bold -FontSize 15 -Color '17365D'
    }
    $table = WordTable -InputObject $reviewRows -Style GridTable4Accent1 `
        -Layout AutoFitToWindow -PassThru
    $table | Get-OfficeWordTableCell | ForEach-Object {
        $_.MarginTopCentimeters = 0.14
        $_.MarginBottomCentimeters = 0.14
    }
    WordParagraph {
        WordParagraphStyle -SpacingBeforePoints 16 -SpacingAfterPoints 8 -KeepWithNext $true
        WordText 'Before placing the order' -Bold -FontSize 15 -Color '17365D'
    }
    WordList -Style Bulleted {
        WordListItem -Text 'Confirm stock, quote expiry and the date the equipment is needed.'
        WordListItem -Text 'Add freight and tax to compare the landed cost.'
        WordListItem -Text 'Record the chosen supplier, reason and approval owner here.'
    }
}
Export-OfficeDocumentPdf -InputPath $docx -Path $pdf

The cell padding makes the table readable without adding empty rows. SpacingBeforePoints separates the next heading from the table, and KeepWithNext prevents a heading from being stranded at the bottom of a page when you add more offers.

Leave the calculations in the workbook

Use the numeric objects for Excel. The table gives the buyer filters, while a frozen header and sensible column widths make it easier to work through a longer list. Each price keeps its supplied decimal places, with at least two displayed for these USD quotes.

New-OfficeExcel -Path $xlsx {
    ExcelSheet 'Offers' {
        ExcelGridlines -Hide
        ExcelCell -Address A1 -Value 'Supplier offers / USD per unit'
        ExcelRow -Row 1 -Height 30 -Bold $true
        ExcelCell -Address A2 -Value 'Freight and tax excluded. Compare delivery before ordering.'
        ExcelTable -InputObject $offers -StartRow 4 -TableName SupplierOffers `
            -TableStyle TableStyleMedium2
        for ($row = 5; $row -lt 5 + $offers.Count; $row++) {
            $price = $offers[$row - 5].UnitPriceUsd
            $places = $price.ToString($priceFormat, $culture).Split('.')[1].Length
            ExcelCell -Row $row -Column 3 -Value $price -NumberFormat ('0.' + ('0' * $places))
            ExcelRow -Row $row -Height 24
        }
        ExcelColumn -Column 1 -Width 25
        ExcelColumn -Column 2 -Width 22
        ExcelColumn -Column 3 -AutoFit
        ExcelColumn -Column 4 -Width 16
        ExcelFreeze -TopRows 4
    }
}
Supplier workbook with filterable offers and numeric prices

The three files are in Output/SupplierReview. Open the workbook to compare the offers, add the decision to the Word document, and export that edited document again when you want a final PDF. If the supplier sends an updated table, rerun the blocks to rebuild the comparison from the new data. Keep your completed approval notes separately, since rerunning writes new report files at these paths.

You can use the same approach for a software renewal or a parts list: change the input columns, keep the fields you calculate with numeric, and explain the actual decision in the document. To share the PDF and workbook together, continue with reviewing report attachments before sending email.

API used on this page

Example source

Download source