Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Who owns this repository, and who GitHub asks to review a change to it.
#
# One owner, one line. Finer-grained rules would be fiction here: every path
# below has the same owner, and a list that pretends otherwise ages into a claim
# nobody checks.
#
# What this file DOES do
# ----------------------
# A pull request opened by anyone else automatically requests a review from the
# owner. That is the whole reason it exists: an outside contribution should not
# sit unnoticed because nobody was asked. This project accepts translations of
# the window and evidence from machines that are not ours, so that path is real
# rather than hypothetical - see CONTRIBUTING.md.
#
# What it does NOT do
# -------------------
# GitHub never requests a review from the person who opened the pull request, and
# nobody can approve their own. So on a change written by the owner this file is
# silent by design - and a rule that demands a code-owner approval would, on such
# a change, demand one from somebody who does not exist. That combination freezes
# the repository: no pull request could ever be merged. The ruleset on the
# default branch leaves `require_code_owner_review` off, and it has to stay off
# for as long as this file names one person.
#
# What actually guards the code today
# -----------------------------------
# Measured on 2026-09-23: the default branch carries one active ruleset. It
# refuses deletion and force pushes, takes every change through a pull request
# with no approval required, and requires six named checks to pass -
# `build and the tests that do not need this machine`, `Semgrep`,
# `Dependency review`, `Analyse csharp`, `Analyse actions` and `submit-nuget`.
# So a red check blocks a merge and a missing review does not. That is a weaker
# guarantee than a second pair of eyes, and it is stated plainly rather than
# dressed up.
#
# Syntax note: gitignore-style patterns, with three exceptions - a pattern may not
# start with `#`, `!` does not negate, and `[ ]` character ranges do not work.

* @donislawdev
8 changes: 8 additions & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# The sponsor button GitHub shows on the repository.
#
# One custom address rather than a platform, because the page behind it is ours
# and can say what the money is for.
#
# The quoting is not decoration. A YAML value holding a colon has to be quoted or
# the parser reads it as a mapping, and every https address holds one.
custom: ["https://donislawdev.com/support/"]
114 changes: 114 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
name: Bug report
description: Something in Better Windows Services does not work as expected
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to report this. The version, whether the session had
administrator rights, and the output the tool printed are the three most useful
things you can give us.

**If the tool and `sc.exe` disagree about a service, use the "Disagreement with
sc.exe" template instead.** It asks for exactly the output that settles it.

**Some answers are not bugs.** Without administrator rights Windows lists fewer
services and refuses more of what it lists, and the tool says so at the top of
both the window and the command line. Exit code 3 means a step did not get where
it was going, usually because the service manager refused, and 5 means a snapshot
comparison found differences. Report them if you believe the answer itself is
wrong.
- type: textarea
id: version
attributes:
label: Version
description: >-
`bws --version` prints it - paste the first two lines. For the window, run this
in PowerShell next to the executable:
`(Get-Item .\BetterWindowsServices.exe).VersionInfo.ProductVersion`.
placeholder: |
bws 0.1.0
snapshot schema 4
render: text
validations:
required: true
- type: dropdown
id: surface
attributes:
label: How were you running it?
description: >-
The window and the command line are two clients of one engine, so a bug in one
is often a bug in both. Which one you saw it in narrows it down.
options:
- "Window (BetterWindowsServices.exe)"
- "Command line (bws.exe)"
- "Both"
validations:
required: true
- type: dropdown
id: elevated
attributes:
label: Was it running as administrator?
description: >-
This changes what Windows hands over, so it splits most reports in half. When it
is not, the window says "Running without administrator rights" in its status
line and the command line prints a warning before anything else.
options:
- "Yes, as administrator"
- "No"
- "Not sure"
validations:
required: true
- type: textarea
id: what
attributes:
label: What happened?
description: What you expected, and what happened instead.
validations:
required: true
- type: textarea
id: steps
attributes:
label: The command, or the steps
description: >-
The smallest thing that triggers it. A single `bws` command line is ideal, so
paste it rather than describing it. For the window, the query you typed and
what you clicked.
render: shell
validations:
required: true
- type: textarea
id: plan
attributes:
label: If a plan was involved - the preview, and what happened
description: >-
The preview and the execution are the same plan, so any difference between what
`--dry-run` or the plan panel showed and what the run did is the worst bug this
product can have. Paste the preview, then say what actually happened.
render: shell
- type: input
id: exit
attributes:
label: Exit code
description: >-
`$LASTEXITCODE` in PowerShell, or `echo %ERRORLEVEL%` in cmd, right after the
command. The codes are part of this tool's contract, so a wrong one is a bug on
its own even when the output looked right.
placeholder: "3"
- type: textarea
id: output
attributes:
label: What the tool printed
description: >-
The output with `--json` is the most useful. Before pasting: it names services,
accounts, file paths and sometimes other machines, and this issue is public.
Read it first and remove anything you would rather not publish.
render: shell
- type: input
id: windows
attributes:
label: Windows version and display language
description: >-
Output of `winver`, and the display language if it is not English. Display
names and account names are translated, and the tool must not depend on either.
placeholder: "Windows Server 2022, German"
17 changes: 17 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Problems belong here, on the issue tracker, where the next person hitting the
# same thing can find the answer. There is deliberately no link out to a support
# page: the only other channel is for vulnerabilities, which must not be public
# until there is a fix.
#
# Blank issues are off because every template below asks for the few things that
# make a report answerable - the version, the surface, whether the session had
# administrator rights, and the output the tool already printed. A question that
# fits none of them still has a home: "Question or problem".
blank_issues_enabled: false
contact_links:
- name: Report a security vulnerability
url: https://github.com/donislawdev/BetterWindowsServices/security/advisories/new
about: Please report security issues privately, never as a public issue. SECURITY.md says what is in scope.
- name: Read the documentation first
url: https://betterwindowsservices.donislawdev.com/
about: The command reference, the query language and the honest limits are all there.
45 changes: 45 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Feature request
description: Suggest an improvement or a new capability
labels: ["enhancement"]
body:
- type: textarea
id: problem
attributes:
label: What problem would this solve?
description: The administration task that is awkward today, and on what kind of machine.
validations:
required: true
- type: textarea
id: idea
attributes:
label: Proposed solution
description: What you would like the tool to do.
validations:
required: true
- type: textarea
id: today
attributes:
label: What you do today instead
description: >-
sc.exe, PowerShell, services.msc, a script of your own - and what it costs you.
- type: checkboxes
id: scope
attributes:
label: Scope
description: >-
Three things this project has decided and will not revisit without a new
argument. Saying so here saves you writing a proposal that was never going to be
accepted.
options:
- label: This does not need the tool to reach the network on its own. No telemetry, no update check, no crash reporting and no client of any service - the tool is meant for production servers. The one exception is `--follow-network`, which lets it look at a launch path on another machine's share when you pass it, and it is off by default.
required: true
- label: This does not change anything without a plan. Every change builds a plan that can be previewed, turned into a command line and undone, and the preview is exactly what the execution does. There is no second path for a change, not even a quick one.
required: true
- label: This is about Windows services on the machine the tool runs on. Remote management is not in this version - to compare two machines, take a snapshot on each and compare the two files.
required: true
- type: checkboxes
id: surfaces
attributes:
label: Both surfaces
options:
- label: I understand that a capability lives in the engine and appears in both the window and the command line, rather than in one of them.
53 changes: 53 additions & 0 deletions .github/ISSUE_TEMPLATE/question.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: Question or problem
description: Ask about using the tool, or report something that does not fit the other templates
labels: ["question"]
body:
- type: markdown
attributes:
value: |
Questions belong here rather than in private mail, because the next person to hit
the same thing can find the answer.

If it turns out to be a defect we will relabel it - you do not have to decide that
first. The same goes the other way: "the tool lists fewer services when I run it
without administrator rights, is that expected?" is a fair question, and the
answer is often yes with a reason.
- type: textarea
id: question
attributes:
label: What are you trying to do?
description: The task, and what you have tried so far.
validations:
required: true
- type: input
id: version
attributes:
label: Version
description: >-
If the tool is already on the machine, `bws --version` prints it.
placeholder: "bws 0.1.0, snapshot schema 4"
- type: dropdown
id: surface
attributes:
label: Which surface, if it matters
options:
- "Window (BetterWindowsServices.exe)"
- "Command line (bws.exe)"
- "Both"
- "Not relevant"
- type: dropdown
id: elevated
attributes:
label: Was it running as administrator?
options:
- "Yes, as administrator"
- "No"
- "Not sure"
- type: textarea
id: extra
attributes:
label: The command or the output, if there is one
description: >-
Paste it rather than describing it. Anything you paste is public, and the output
names services, accounts and paths, so check it before it goes in.
render: shell
82 changes: 82 additions & 0 deletions .github/ISSUE_TEMPLATE/sc_disagreement.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: Disagreement with sc.exe
description: The tool and the sc.exe that ships with Windows say different things about a service
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
`sc.exe` is the reference this tool is checked against, entry by entry, on the
machines it is built on. Yours is different, and a disagreement on your machine
is a bug here until shown otherwise - even when every test passes.

Run all of the commands below **in the same session**, so both tools had the same
rights.
- type: input
id: name
attributes:
label: Service name
description: >-
The internal name, as `sc query` shows it after SERVICE_NAME, and not the display
name. Display names are translated into the language of the machine, and the tool
never identifies a service by one.
placeholder: "Spooler"
validations:
required: true
- type: dropdown
id: elevated
attributes:
label: Was the session running as administrator?
description: >-
Without administrator rights Windows refuses some reads, and the two tools may
report a refusal differently. That is worth knowing before anything else.
options:
- "Yes, as administrator"
- "No"
- "Not sure"
validations:
required: true
- type: textarea
id: difference
attributes:
label: What differs?
description: >-
The field and the two values, in a sentence. For example, sc qc says the start
type is DEMAND_START and the tool says automatic.
validations:
required: true
- type: textarea
id: bws
attributes:
label: The output of bws show NAME --json
render: json
validations:
required: true
- type: textarea
id: sc
attributes:
label: The output of sc qc NAME, sc query NAME and sc qtriggerinfo NAME
description: >-
All three, one after another. Before pasting: they carry the launch path and the
account the service runs as, which can name a user or a machine, and this issue
is public. Remove anything you would rather not publish.
render: shell
validations:
required: true
- type: textarea
id: version
attributes:
label: Version
description: "`bws --version` prints it - paste the first two lines."
placeholder: |
bws 0.1.0
snapshot schema 4
render: text
validations:
required: true
- type: input
id: windows
attributes:
label: Windows version and display language
description: >-
Output of `winver`, and the display language if it is not English.
placeholder: "Windows Server 2022, German"
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ Nothing has been released yet. Everything below is what the tool does today.

### Added

- **A *Donate* button in the window**, at the right end of the row above the search box. It
opens the project's support page in your browser and says so before it is pressed - the tool
itself still opens no connection, your browser is what connects. In a window running as
administrator the page is handed to the desktop to open, so the browser starts with your own
rights rather than the tool's. If the page cannot be opened, the status line says why and
gives the address to type in. The window keeps answering while Windows opens the page, and if
Windows has not finished after ten seconds the status line says so - the page may still open
by itself.

- **`bws license`, and `bws license --components`.** What the program is licensed under, that it
comes with no warranty, where the full text is, and what it carries that somebody else wrote.
The second form turns that into every component with its version, its licence and where it came
Expand Down
5 changes: 3 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,9 @@ a declaration:
command line tool writes to the data channel.
- **The core writes nothing to the console.** It returns results, and the layer above decides what
happens to them.
- **A shipped assembly starts no process**, with one named exception in the window, in one file:
restarting itself as administrator.
- **A shipped assembly starts no process**, with two named exceptions in the window, each in a file
of its own: restarting itself as administrator, and handing the support page to the browser -
through the desktop, when the window has administrator rights, so that the browser does not.
- **Every broad `catch`, every `async void`, every native call that drops its answer, and every
place that does two things at once is on a list with the argument for it beside it** - and the
list may not name a place that stopped doing it.
Expand Down
Loading
Loading