503 lines
11 KiB
Go
503 lines
11 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"os/exec"
|
|
"regexp"
|
|
"runtime"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// Software holds information about installed software
|
|
type Software struct {
|
|
Source string `json:"source"`
|
|
Name string `json:"name"`
|
|
Version string `json:"version"`
|
|
InstallDate string `json:"install_date"`
|
|
}
|
|
|
|
func main() {
|
|
var softwareList []Software
|
|
|
|
if runtime.GOOS == "windows" {
|
|
softwareList = append(softwareList, enumerateWindows()...)
|
|
} else if runtime.GOOS == "linux" {
|
|
softwareList = append(softwareList, enumerateLinux()...)
|
|
}
|
|
|
|
output, err := json.MarshalIndent(softwareList, "", " ")
|
|
if err != nil {
|
|
log.Println("Error marshalling software list:", err)
|
|
return
|
|
}
|
|
fmt.Println(string(output))
|
|
}
|
|
|
|
// Add to the enumerateWindows function
|
|
func enumerateWindows() []Software {
|
|
var softwareList []Software
|
|
|
|
// Winget
|
|
softwareList = append(softwareList, enumerateWinget()...)
|
|
|
|
// Chocolatey
|
|
softwareList = append(softwareList, enumerateChocolatey()...)
|
|
|
|
// Scoop
|
|
softwareList = append(softwareList, enumerateScoop()...)
|
|
|
|
// Common Windows Installations
|
|
softwareList = append(softwareList, enumerateCommonWindows()...)
|
|
|
|
// NuGet
|
|
softwareList = append(softwareList, enumerateNuGet()...)
|
|
|
|
// Microsoft Store
|
|
softwareList = append(softwareList, enumerateMicrosoftStore()...)
|
|
|
|
return softwareList
|
|
}
|
|
|
|
// Add to the enumerateLinux function
|
|
func enumerateLinux() []Software {
|
|
var softwareList []Software
|
|
|
|
// APT
|
|
softwareList = append(softwareList, enumerateApt()...)
|
|
|
|
// Snap
|
|
softwareList = append(softwareList, enumerateSnap()...)
|
|
|
|
// Pip
|
|
softwareList = append(softwareList, enumeratePip()...)
|
|
|
|
// NPM
|
|
softwareList = append(softwareList, enumerateNpm()...)
|
|
|
|
// Flatpak
|
|
softwareList = append(softwareList, enumerateFlatpak()...)
|
|
|
|
// RPM
|
|
softwareList = append(softwareList, enumerateRpm()...)
|
|
|
|
// Pacman
|
|
softwareList = append(softwareList, enumeratePacman()...)
|
|
|
|
// Homebrew
|
|
softwareList = append(softwareList, enumerateHomebrew()...)
|
|
|
|
// Conda
|
|
softwareList = append(softwareList, enumerateConda()...)
|
|
|
|
return softwareList
|
|
}
|
|
|
|
func enumerateNuGet() []Software {
|
|
var softwareList []Software
|
|
|
|
output, err := runCommand("nuget", "list", "-AllVersions")
|
|
if err != nil {
|
|
log.Println("Error enumerating NuGet packages:", err)
|
|
return softwareList
|
|
}
|
|
|
|
lines := strings.Split(output, "\n")
|
|
for _, line := range lines {
|
|
parts := strings.Fields(line)
|
|
if len(parts) < 2 {
|
|
continue
|
|
}
|
|
softwareList = append(softwareList, Software{
|
|
Source: "nuget",
|
|
Name: parts[0],
|
|
Version: parts[1],
|
|
})
|
|
}
|
|
|
|
return softwareList
|
|
}
|
|
|
|
func enumerateMicrosoftStore() []Software {
|
|
var softwareList []Software
|
|
|
|
output, err := runCommand("powershell", "Get-AppxPackage", "|", "Select-Object", "Name,PackageFullName,InstallDate")
|
|
if err != nil {
|
|
log.Println("Error enumerating Microsoft Store packages:", err)
|
|
return softwareList
|
|
}
|
|
|
|
lines := strings.Split(output, "\n")
|
|
for _, line := range lines {
|
|
parts := strings.Fields(line)
|
|
if len(parts) < 3 {
|
|
continue
|
|
}
|
|
softwareList = append(softwareList, Software{
|
|
Source: "microsoft store",
|
|
Name: parts[0],
|
|
Version: parts[1],
|
|
InstallDate: parseInstallDate(parts[2]),
|
|
})
|
|
}
|
|
|
|
return softwareList
|
|
}
|
|
|
|
func enumerateFlatpak() []Software {
|
|
var softwareList []Software
|
|
|
|
output, err := runCommand("flatpak", "list")
|
|
if err != nil {
|
|
log.Println("Error enumerating Flatpak packages:", err)
|
|
return softwareList
|
|
}
|
|
|
|
lines := strings.Split(output, "\n")
|
|
for _, line := range lines {
|
|
parts := strings.Fields(line)
|
|
if len(parts) < 2 {
|
|
continue
|
|
}
|
|
softwareList = append(softwareList, Software{
|
|
Source: "flatpak",
|
|
Name: parts[0],
|
|
Version: parts[1],
|
|
})
|
|
}
|
|
|
|
return softwareList
|
|
}
|
|
|
|
func enumerateRpm() []Software {
|
|
var softwareList []Software
|
|
|
|
output, err := runCommand("rpm", "-qa", "--queryformat", "%{NAME} %{VERSION}\n")
|
|
if err != nil {
|
|
log.Println("Error enumerating RPM packages:", err)
|
|
return softwareList
|
|
}
|
|
|
|
lines := strings.Split(output, "\n")
|
|
for _, line := range lines {
|
|
parts := strings.Fields(line)
|
|
if len(parts) < 2 {
|
|
continue
|
|
}
|
|
softwareList = append(softwareList, Software{
|
|
Source: "rpm",
|
|
Name: parts[0],
|
|
Version: parts[1],
|
|
})
|
|
}
|
|
|
|
return softwareList
|
|
}
|
|
|
|
func enumeratePacman() []Software {
|
|
var softwareList []Software
|
|
|
|
output, err := runCommand("pacman", "-Q")
|
|
if err != nil {
|
|
log.Println("Error enumerating Pacman packages:", err)
|
|
return softwareList
|
|
}
|
|
|
|
lines := strings.Split(output, "\n")
|
|
for _, line := range lines {
|
|
parts := strings.Fields(line)
|
|
if len(parts) < 2 {
|
|
continue
|
|
}
|
|
softwareList = append(softwareList, Software{
|
|
Source: "pacman",
|
|
Name: parts[0],
|
|
Version: parts[1],
|
|
})
|
|
}
|
|
|
|
return softwareList
|
|
}
|
|
|
|
func enumerateHomebrew() []Software {
|
|
var softwareList []Software
|
|
|
|
output, err := runCommand("brew", "list", "--versions")
|
|
if err != nil {
|
|
log.Println("Error enumerating Homebrew packages:", err)
|
|
return softwareList
|
|
}
|
|
|
|
lines := strings.Split(output, "\n")
|
|
for _, line := range lines {
|
|
parts := strings.Fields(line)
|
|
if len(parts) < 2 {
|
|
continue
|
|
}
|
|
softwareList = append(softwareList, Software{
|
|
Source: "homebrew",
|
|
Name: parts[0],
|
|
Version: parts[1],
|
|
})
|
|
}
|
|
|
|
return softwareList
|
|
}
|
|
|
|
func enumerateConda() []Software {
|
|
var softwareList []Software
|
|
|
|
output, err := runCommand("conda", "list", "--json")
|
|
if err != nil {
|
|
log.Println("Error enumerating Conda packages:", err)
|
|
return softwareList
|
|
}
|
|
|
|
var condaPackages []map[string]interface{}
|
|
err = json.Unmarshal([]byte(output), &condaPackages)
|
|
if err != nil {
|
|
log.Println("Error parsing Conda JSON output:", err)
|
|
return softwareList
|
|
}
|
|
|
|
for _, pkg := range condaPackages {
|
|
softwareList = append(softwareList, Software{
|
|
Source: "conda",
|
|
Name: pkg["name"].(string),
|
|
Version: pkg["version"].(string),
|
|
})
|
|
}
|
|
|
|
return softwareList
|
|
}
|
|
|
|
func runCommand(cmd string, args ...string) (string, error) {
|
|
out, err := exec.Command(cmd, args...).Output()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return string(out), nil
|
|
}
|
|
|
|
func parseInstallDate(dateString string) string {
|
|
layout := "2006-01-02"
|
|
date, err := time.Parse(layout, dateString)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return date.Format(layout)
|
|
}
|
|
|
|
func enumerateWinget() []Software {
|
|
var softwareList []Software
|
|
|
|
output, err := runCommand("winget", "list", "--source", "winget")
|
|
if err != nil {
|
|
log.Println("Error enumerating Winget packages:", err)
|
|
return softwareList
|
|
}
|
|
|
|
lines := strings.Split(output, "\n")
|
|
for _, line := range lines {
|
|
parts := regexp.MustCompile(`\s+`).Split(line, -1)
|
|
if len(parts) < 4 {
|
|
continue
|
|
}
|
|
softwareList = append(softwareList, Software{
|
|
Source: "winget",
|
|
Name: parts[0],
|
|
Version: parts[1],
|
|
})
|
|
}
|
|
|
|
return softwareList
|
|
}
|
|
|
|
func enumerateChocolatey() []Software {
|
|
var softwareList []Software
|
|
|
|
output, err := runCommand("choco", "list", "--local-only")
|
|
if err != nil {
|
|
log.Println("Error enumerating Chocolatey packages:", err)
|
|
return softwareList
|
|
}
|
|
|
|
lines := strings.Split(output, "\n")
|
|
for _, line := range lines {
|
|
parts := strings.Split(line, "|")
|
|
if len(parts) < 2 {
|
|
continue
|
|
}
|
|
softwareList = append(softwareList, Software{
|
|
Source: "chocolatey",
|
|
Name: parts[0],
|
|
Version: parts[1],
|
|
})
|
|
}
|
|
|
|
return softwareList
|
|
}
|
|
|
|
func enumerateScoop() []Software {
|
|
var softwareList []Software
|
|
|
|
output, err := runCommand("scoop", "list")
|
|
if err != nil {
|
|
log.Println("Error enumerating Scoop packages:", err)
|
|
return softwareList
|
|
}
|
|
|
|
lines := strings.Split(output, "\n")
|
|
for _, line := range lines {
|
|
if strings.HasPrefix(line, "Installed apps") {
|
|
continue
|
|
}
|
|
parts := strings.Fields(line)
|
|
if len(parts) < 2 {
|
|
continue
|
|
}
|
|
softwareList = append(softwareList, Software{
|
|
Source: "scoop",
|
|
Name: parts[0],
|
|
Version: parts[1],
|
|
})
|
|
}
|
|
|
|
return softwareList
|
|
}
|
|
|
|
func enumerateCommonWindows() []Software {
|
|
var softwareList []Software
|
|
|
|
output, err := runCommand("powershell", "Get-WmiObject", "-Class", "Win32_Product", "|", "Select-Object", "Name,Version,InstallDate")
|
|
if err != nil {
|
|
log.Println("Error enumerating common Windows installations:", err)
|
|
return softwareList
|
|
}
|
|
|
|
lines := strings.Split(output, "\n")
|
|
for _, line := range lines {
|
|
parts := strings.Fields(line)
|
|
if len(parts) < 3 {
|
|
continue
|
|
}
|
|
softwareList = append(softwareList, Software{
|
|
Source: "common windows installation",
|
|
Name: parts[0],
|
|
Version: parts[1],
|
|
InstallDate: parseInstallDate(parts[2]),
|
|
})
|
|
}
|
|
|
|
return softwareList
|
|
}
|
|
|
|
func enumerateApt() []Software {
|
|
var softwareList []Software
|
|
|
|
output, err := runCommand("dpkg-query", "-W", "-f=${binary:Package} ${Version} ${Installed-Size}\n")
|
|
if err != nil {
|
|
log.Println("Error enumerating APT packages:", err)
|
|
return softwareList
|
|
}
|
|
|
|
lines := strings.Split(output, "\n")
|
|
for _, line := range lines {
|
|
parts := strings.Fields(line)
|
|
if len(parts) < 2 {
|
|
continue
|
|
}
|
|
softwareList = append(softwareList, Software{
|
|
Source: "apt",
|
|
Name: parts[0],
|
|
Version: parts[1],
|
|
})
|
|
}
|
|
|
|
return softwareList
|
|
}
|
|
|
|
func enumerateSnap() []Software {
|
|
var softwareList []Software
|
|
|
|
output, err := runCommand("snap", "list")
|
|
if err != nil {
|
|
log.Println("Error enumerating Snap packages:", err)
|
|
return softwareList
|
|
}
|
|
|
|
lines := strings.Split(output, "\n")
|
|
for _, line := range lines {
|
|
parts := strings.Fields(line)
|
|
if len(parts) < 3 {
|
|
continue
|
|
}
|
|
softwareList = append(softwareList, Software{
|
|
Source: "snap",
|
|
Name: parts[0],
|
|
Version: parts[1],
|
|
})
|
|
}
|
|
|
|
return softwareList
|
|
}
|
|
|
|
func enumeratePip() []Software {
|
|
var softwareList []Software
|
|
|
|
output, err := runCommand("pip", "list", "--format=json")
|
|
if err != nil {
|
|
log.Println("Error enumerating Pip packages:", err)
|
|
return softwareList
|
|
}
|
|
|
|
var pipPackages []map[string]string
|
|
err = json.Unmarshal([]byte(output), &pipPackages)
|
|
if err != nil {
|
|
log.Println("Error parsing Pip JSON output:", err)
|
|
return softwareList
|
|
}
|
|
|
|
for _, pkg := range pipPackages {
|
|
softwareList = append(softwareList, Software{
|
|
Source: "pip",
|
|
Name: pkg["name"],
|
|
Version: pkg["version"],
|
|
})
|
|
}
|
|
|
|
return softwareList
|
|
}
|
|
|
|
func enumerateNpm() []Software {
|
|
var softwareList []Software
|
|
|
|
output, err := runCommand("npm", "list", "-g", "--depth=0", "--json")
|
|
if err != nil {
|
|
log.Println("Error enumerating NPM packages:", err)
|
|
return softwareList
|
|
}
|
|
|
|
var npmPackages map[string]interface{}
|
|
err = json.Unmarshal([]byte(output), &npmPackages)
|
|
if err != nil {
|
|
log.Println("Error parsing NPM JSON output:", err)
|
|
return softwareList
|
|
}
|
|
|
|
dependencies := npmPackages["dependencies"].(map[string]interface{})
|
|
for name, info := range dependencies {
|
|
infoMap := info.(map[string]interface{})
|
|
version := infoMap["version"].(string)
|
|
softwareList = append(softwareList, Software{
|
|
Source: "npm",
|
|
Name: name,
|
|
Version: version,
|
|
})
|
|
}
|
|
|
|
return softwareList
|
|
}
|