Add goinfo and gosoft

This commit is contained in:
tabledevil
2025-03-25 08:16:04 +01:00
parent 75fdf8cc9b
commit 13f060433c
4 changed files with 557 additions and 0 deletions

BIN
tools/go/gosoft/gosoft.exe Executable file

Binary file not shown.

502
tools/go/gosoft/gosoft.go Normal file
View File

@@ -0,0 +1,502 @@
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
}