A PowerShell module for browser automation using the Chrome DevTools Protocol. Built on PuppeteerSharp, it works with PowerShell 5.1+ on Windows, Linux, and macOS.
Install-Module Pup
Install-PupBrowser- Start-PupBrowser - Launch browser instance
- Stop-PupBrowser - Close browser
- Get-PupBrowser - Get running browsers
- Install-PupBrowser - Download browser
- Uninstall-PupBrowser - Remove browser
- New-PupPage - Create new page/tab
- Get-PupPage - Get open pages
- Remove-PupPage - Close page
- Move-PupPage - Navigate to URL
- Invoke-PupPageBack - Go back
- Invoke-PupPageForward - Go forward
- Invoke-PupPageReload - Reload page
- Invoke-PupPageScroll - Scroll page
- Invoke-PupScript - Execute JavaScript (supports
-Frame) - Set-PupViewport - Set viewport size
- Get-PupSource - Get page HTML (supports
-Frame)
- Get-PupFrame - Get frames/iframes from page
- Set-PupPermission - Set browser permissions (geolocation, notifications, etc.)
- Get-PupPermission - Get browser permission state
- Find-PupElements - Find elements by selector (supports
-Frame) - Wait-PupElement - Wait for element (supports
-Frame) - Invoke-PupElementClick - Click element
- Invoke-PupElementHover - Hover over element
- Invoke-PupElementFocus - Focus element
- Invoke-PupElementScroll - Scroll element
- Set-PupElement - Set element text
- Set-PupElementValue - Set element value
- Set-PupElementAttribute - Set attribute
- Get-PupElementValue - Get element value
- Get-PupElementAttribute - Get attribute
- Get-PupElementSelector - Get CSS selector
- Get-PupElementPattern - Get selector patterns
- Select-PupElementOption - Select dropdown option
- Start-PupRecording - Start recording interactions
- Stop-PupRecording - Stop recording
- Get-PupRecording - Get recorded events
- Clear-PupRecording - Clear recorded events
- Invoke-PupRecording - Replay recorded interactions
- ConvertTo-PupScript - Convert events to script
- Get-PupPageScreenshot - Capture page screenshot
- Get-PupElementScreenshot - Capture element screenshot
- Export-PupPdf - Export page as PDF
- Get-PupCookie - Get cookies
- Set-PupCookie - Set cookie
- Remove-PupCookie - Remove cookies
- Get-PupStorage - Get local/session storage
- Set-PupStorage - Set storage item
- Clear-PupStorage - Clear storage
- Invoke-PupHttpFetch - Make HTTP request
- Set-PupHttpHeader - Set request headers
- Set-PupHttpAuth - Set HTTP authentication
- Get-PupNetwork - Get network requests
- Get-PupWebSocket - Get WebSocket connections
- Send-PupWebSocketMessage - Send WebSocket message
- Export-PupSession - Export session (cookies, storage)
- Import-PupSession - Import session
- Send-PupKey - Send keyboard input
- Send-PupFile - Upload file
- Set-PupBrowserHandler - Handle browser events (popups, page created/closed)
- Get-PupBrowserHandler - Get active browser handlers
- Remove-PupBrowserHandler - Remove browser handler
- Set-PupPageHandler - Handle page events (dialogs, console, requests)
- Get-PupPageHandler - Get active page handlers
- Remove-PupPageHandler - Remove page handler
- Enter-PupConsole - Interactive console mode
- Get-PupConsole - Get console messages
- Invoke-PupCdpMessage - Send raw CDP command
- Get-PupCertificate - Get page certificate
This example scrapes Ubuntu security notices from https://ubuntu.com/security/notices and returns the date and link to security issues.
Import-Module Pup
$page = start-PupBrowser | New-PupPage -Url https://ubuntu.com/security/notices If you look at the opened page in the browser, you see that there are 10 notices per page. So we need a list that contains all those, so that we can iterate over it. Copy the first link name, which at this time is USN-8015-3: Linux kernel (FIPS) vulnerabilities.
# Try with different depths, and try to go as deep as possible while at the same time catching all 10 items.
$page | find-pupelements -Text "USN-8015-3: Linux kernel (FIPS) vulnerabilities" | get-PupElementPattern -Depth 3
# Type Selector MatchCount Description
# ---- -------- ---------- -----------
# ByClass section.p-section--shallow 10 Elements with same tag and…
# ByParentClass .col-9 section 10 All section inside .col-9
# ByAncestorId #notices-list section 10 All section under #notices…
# ByStructure div.col-9 section 10 Elements in repeating div.…
# ByTag section 16 All section elements
$listSelector = "#notices-list section"If we first get the first element by using the $listSelector, we can get the element that holds the date-text, and see its selector.
$page | find-pupelements -Selector $listSelector -First | Find-PupElements -TextContains "6 february"
# Selector : div.row > div.col-6 > p.u-text--muted
# Index : 0
# FoundTime : 2026-02-09 20:21:09
# TagName : P
# InnerText : 6 February 2026
# InnerHTML : 6 February 2026
# Id :
# IsVisible : False
$dateSelector = "div.row > div.col-6 > p.u-text--muted"We use the $listSelector again, and get the element that holds the link-text, and see its selector.
$page | find-pupelements -Selector $listSelector -First | Find-PupElements -TextContains "USN-8015-3: Linux kernel (FIPS) vulnerabilities"
# ElementId : 17fa5859-2293-4913-87db-4fc0049e3f89
# Selector : div.u-fixed-width > h3.u-no-margin > a
# Index : 0
# FoundTime : 2026-02-09 20:34:23
# TagName : A
# InnerText : USN-8015-3: Linux kernel (FIPS) vulnerabilities
# InnerHTML : USN-8015-3: Linux kernel (FIPS) vulnerabilities
# Id :
# IsVisible : False
$linkSelector = "div.u-fixed-width > h3.u-no-margin > a"We need the selector to next page in order to scrape multiple pages.
# it doesn't show on the page, but if you look in source it's actually "Next page".
# the selector from Find-PupElements doesn't look great, but if we run the element through Get-PupElementPattern we get better ones. We can choose any with 1 match.
$page | find-pupelements -Text "Next page" | Get-PupElementPattern
# Type Selector MatchCount Description
# ---- -------- ---------- -----------
# ByClass i.p-icon--chevron-down 3 Elements with same tag and classes
# ByTag i 13 All i elements
# ByParentClass .p-pagination__link--next i 1 All i inside .p-pagination__link--next
# ByAncestorId #notices-list div > ol > li > a > i 1 All i under #notices-list
# ByStructure li.p-pagination__item a > i 1 Elements in repeating li.p-pagination__item containers
$nextPageSelector = ".p-pagination__link--next i"Now we have everything that is needed for the script. We only need the Ubuntu notices from the last month, so we'll stop when we get an older notice.
$url = "https://ubuntu.com"
$listSelector = "#notices-list section"
$dateSelector = "div.row > div.col-6 > p.u-text--muted"
$linkSelector = "div.u-fixed-width > h3.u-no-margin > a"
$nextPageSelector = ".p-pagination__link--next i"
# check notices from 1 month back.
$fromDate = (Get-Date).AddMonths(-1)
$browser = Start-PupBrowser -Headless
$page = New-PupPage -Url "$url/security/notices"
$date = Get-Date
# while found date is not older than 1 month
while ($date -gt $fromDate) {
$page | Find-PupElements -WaitForLoad -Selector $listSelector | ForEach-Object {
$date = [datetime]($_ | Find-PupElements -Selector $dateSelector).InnerHTML.Trim()
$href = $_ | Find-PupElements -Selector $linkSelector | Get-PupElementAttribute -Name href
[PSCustomObject]@{
Date = $date
Link = "$url$href"
}
}
# click next-page link
$page | Find-PupElements -Selector $nextPageSelector | Invoke-PupElementClick
}
$browser | Stop-PupBrowser
See more examples in ./examples
See CONTRIBUTING.md for development setup, testing, and troubleshooting.