EvgDev System Administration Knowledge Base

A collection of practical notes, commands, configuration examples, and troubleshooting solutions for Windows, Linux, MikroTik RouterOS, office hardware, Raspberry Pi, Python, Django, and web development.

These notes are based on real-world system administration and software development experience.

Warning: Some operations described below modify the Windows Registry, boot configuration, firewall state, or router configuration. Always create a backup before making changes on production systems.


Table of Contents

  1. Windows Administration
  2. MikroTik RouterOS
  3. Linux and Python
  4. Raspberry Pi and GPIO
  5. Office Hardware
  6. Django and Web Development

Windows Administration

Useful Windows commands, PowerShell examples, registry fixes, and troubleshooting techniques.

Change the Windows Time Zone from the Command Line

Windows includes the tzutil utility for viewing and changing the system time zone.

Display the current time zone

tzutil /g

List all available time zones

tzutil /l

Set a time zone

For example:

tzutil /s "FLE Standard Time"

The FLE Standard Time zone is commonly used for Eastern European locations.

The command is available in desktop and server editions of Windows.


Display a Saved Wi-Fi Password

Windows can display passwords for wireless networks previously saved on the computer.

List saved Wi-Fi profiles

Open Command Prompt and run:

netsh wlan show profiles

Display information about a specific profile

Replace Wi-Fi-Profile with the actual profile name:

netsh wlan show profile name="Wi-Fi-Profile" key=clear

Look for the following field in the output:

Key Content

The command must be run by a user who has permission to access the saved wireless configuration.


Find the SID of the Current User

A Security Identifier, or SID, is often required when working with permissions or registry keys under HKEY_USERS.

Run:

whoami /user

Example output:

USER INFORMATION
----------------

User Name       SID
=============== =============================================
DOMAIN\User     S-1-5-21-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX-1001

Change the Network Profile Type

Windows classifies network connections as:

Changing the profile may be necessary for Remote Desktop, file sharing, network discovery, or firewall configuration.

Method 1: PowerShell

Open PowerShell as Administrator.

Display all current profiles:

Get-NetConnectionProfile

Example output:

Name             : Unidentified network
InterfaceAlias   : Ethernet 3
InterfaceIndex   : 19
NetworkCategory  : Public
IPv4Connectivity : NoTraffic
IPv6Connectivity : NoTraffic

Change a specific interface to Private:

Set-NetConnectionProfile -InterfaceIndex 19 -NetworkCategory Private

Verify the result:

Get-NetConnectionProfile -InterfaceIndex 19

Change all detected profiles to Private:

Get-NetConnectionProfile |
    Set-NetConnectionProfile -NetworkCategory Private

Warning: Do not set untrusted public networks to Private. A private profile normally enables less restrictive firewall rules.

Method 2: Registry Editor

Open Registry Editor:

regedit.exe

Navigate to:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles

Locate the required profile using its ProfileName value.

Edit the Category DWORD value:

Value Network category
0 Public
1 Private
2 Domain

A domain-authenticated profile is normally assigned automatically by Windows. Manually setting the registry value does not guarantee successful domain authentication.

Method 3: Local Security Policy

Run:

secpol.msc

Open:

Network List Manager Policies

Here you can define network location behavior and restrict users from changing network profiles.


Refresh DNS Caches in an Active Directory Environment

When troubleshooting outdated or incorrect DNS responses, check both the DNS server and the client computer.

Clear the DNS Server cache

Run this command on a Windows Server with the DNS Server role:

dnscmd /clearcache

An alternative PowerShell command is:

Clear-DnsServerCache -Force

Flush the DNS client cache

Run on the affected workstation or server:

ipconfig /flushdns

Re-register the client in DNS

When necessary:

ipconfig /registerdns

Check the Hosts file

The local Hosts file overrides normal DNS resolution:

C:\Windows\System32\drivers\etc\hosts

Old entries in this file can make a valid DNS configuration appear broken.


Configure Automatic Windows Logon

Windows can automatically log in with a local or domain account.

Security warning: This method stores the account password in the registry. Do not use it on an untrusted or shared computer.

Open Registry Editor and navigate to:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon

Create or modify the following string values:

Registry value Example
DefaultUserName username
DefaultPassword password
DefaultDomainName DOMAIN or computer name
AutoAdminLogon 1

If DefaultPassword does not exist:

  1. Right-click an empty area.
  2. Select New → String Value.
  3. Name it DefaultPassword.
  4. Enter the account password as its value.

Restart Windows to test the configuration.

To disable automatic logon, change:

AutoAdminLogon=0

Disable the Recovery Screen After an Unexpected Shutdown

Windows may display a recovery or boot options screen after a power failure, failed boot, or BSOD.

To ignore all recorded boot failures:

bcdedit /set {current} bootstatuspolicy IgnoreAllFailures

To ignore failures caused by an unexpected shutdown:

bcdedit /set {current} bootstatuspolicy IgnoreShutdownFailures

These options may be useful for:

Warning: Disabling recovery screens can hide a genuine boot problem. Use this configuration only when automatic startup is more important than interactive recovery.

To restore the standard policy:

bcdedit /deletevalue {current} bootstatuspolicy

Fix Outlook Starting in Safe Mode

A legacy Outlook installation may repeatedly start in Safe Mode because of an incorrect calendar-related registry value.

First, find the user's SID:

whoami /user

Then open Registry Editor and navigate to:

HKEY_USERS\<USER-SID>\Software\Microsoft\Office\15.0\Outlook\Options\Calendar

Locate the following DWORD value:

Calendar Type

Change its value from:

1

to:

0

Restart Outlook.

Office\15.0 corresponds to Office 2013. Other Office releases use different version numbers, so this fix should not be applied blindly to every Outlook installation.


Troubleshoot an SFC Error Related to termsrv.dll

System File Checker may report that it cannot repair termsrv.dll or a related Terminal Services component.

Start by running:

sfc /scannow

Review the component servicing log:

C:\Windows\Logs\CBS\CBS.log

To extract SFC-related entries:

findstr /c:"[SR]" C:\Windows\Logs\CBS\CBS.log > "%USERPROFILE%\Desktop\sfc-details.txt"

Before editing the registry, repair the Windows component store:

DISM /Online /Cleanup-Image /ScanHealth

Then run:

DISM /Online /Cleanup-Image /RestoreHealth

Restart Windows and run SFC again:

sfc /scannow

Legacy registry workaround

On older Windows versions, the error may reference a component name similar to:

x86_microsoft-windows-t..teconnectionmanager_31bf3856ad364e35_6.0.6001.18000_none_8e9f41c854441762

A historical workaround involved searching for the exact component identifier in Registry Editor, exporting the matching key, and deleting the invalid entry.

High-risk operation: Do not delete Component Based Servicing or WinSxS registry entries unless you have a complete backup and understand the consequences. Incorrect changes can make Windows servicing and updates unusable.

The preferred procedure on supported Windows versions is to use DISM, SFC, Windows Update, or an in-place repair installation.


MikroTik RouterOS

Practical MikroTik commands for configuration exports, interface management, bridge MAC addresses, and connection tracking.

Export the RouterOS Configuration

A RouterOS text export creates a readable .rsc file.

Create an export:

/export file=config-backup

RouterOS creates:

config-backup.rsc

A text export is useful for:

Export sensitive values

To include passwords and other sensitive values:

/export show-sensitive file=config-backup-sensitive

Security warning: A sensitive export may contain Wi-Fi passwords, VPN secrets, user credentials, and other private information. Store it securely and never publish it in a public repository.


Import a RouterOS Configuration

Import a previously created .rsc script:

/import file-name=config-backup.rsc

Depending on the RouterOS version, the shorter syntax may also work:

/import file=config-backup.rsc

A text export is not identical to a binary system backup. Importing a full configuration into a different router model may require manual editing of interface names and hardware-specific settings.


Create a Binary RouterOS Backup

Create a complete binary backup:

/system backup save name=router-backup

Create an encrypted backup:

/system backup save name=router-backup password="StrongBackupPassword"

Restore it with:

/system backup load name=router-backup.backup

Binary backups are best restored to the same router model and a compatible RouterOS version.


Display Wireless Configuration and Saved Passwords

For devices using the legacy Wireless package:

/interface wireless export show-sensitive

For devices using the newer WiFi menu:

/interface wifi export show-sensitive

Without show-sensitive, RouterOS hides passwords and other secrets.

Only administrators with sufficient permissions should be able to display sensitive configuration.


Change the MAC Address of an Interface

Ethernet interface

/interface ethernet set [find name="ether1"] mac-address=02:23:45:67:89:00

Bridge interface

/interface bridge set [find name="bridge1"] \
    admin-mac=02:23:45:67:89:00 \
    auto-mac=no

Legacy wireless interface

/interface wireless set [find name="wlan1"] \
    mac-address=02:23:45:67:89:00

Use a locally administered unicast MAC address. Addresses beginning with 02 are commonly used for manually assigned local MAC addresses.

Change a MAC address in WinBox

  1. Open Interfaces.
  2. Select the required interface.
  3. Open its properties.
  4. Locate MAC Address or Admin. MAC Address.
  5. Enter the new address.
  6. Apply the configuration.

Not every interface type or hardware model allows its physical MAC address to be changed.


Force a Static MAC Address on a Bridge

By default, RouterOS can automatically select the bridge MAC address from one of its member interfaces.

Display bridge information:

/interface bridge print detail

Example:

name="bridge1"
mac-address=4E:A4:50:F4:E7:1C
auto-mac=yes

To keep the current MAC address permanently, configure it as the administrative MAC:

/interface bridge set [find name="bridge1"] \
    admin-mac=4E:A4:50:F4:E7:1C \
    auto-mac=no

Verify the result:

/interface bridge print detail

The bridge should now show:

auto-mac=no
admin-mac=4E:A4:50:F4:E7:1C

A static bridge MAC can help prevent unexpected MAC changes after:


Remove Active Firewall Connections

RouterOS connection tracking keeps active TCP, UDP, and other tracked connections.

Sometimes an existing session must be terminated immediately after changing NAT, routing, firewall, or policy-routing rules.

Remove TCP connections to a destination

/ip firewall connection remove [
    find where dst-address~"8.8.8.8" protocol=tcp
]

One-line version:

/ip firewall connection remove [find where dst-address~"8.8.8.8" protocol=tcp]

Preview matching connections first

/ip firewall connection print where dst-address~"8.8.8.8" protocol=tcp

Always preview the result before using remove on a production router.


Run Python with MikroTik RouterOS

RouterOS does not provide a normal Linux shell with apt, pip, Python virtual environments, or standard Python package management.

There are three practical ways to use Python with MikroTik.

Option 1: Run Python on an External Server

Create a virtual environment on Linux, macOS, Windows, or a VPS:

python3 -m venv venv
source venv/bin/activate
python -m pip install --upgrade pip

Install a RouterOS API library:

pip install librouteros

Python can then connect to the router through:

This is generally the simplest and safest approach.

Option 2: Run Python in a RouterOS Container

Some ARM64 and x86 MikroTik devices can run Linux containers.

A compatible Linux container image can include:

Container support must be explicitly installed and enabled. It also requires enough storage and memory.

Do not run large application workloads on a router unless the device has sufficient resources and the network impact is understood.

Option 3: Use Native RouterOS Scripts

For simple automation, use the built-in RouterOS scripting language:

/system script add name=test-script source={
    :log info "RouterOS script started"
}

Run the script:

/system script run test-script

Native scripts are suitable for:


Linux and Python

Practical Linux administration examples for Python applications and systemd services.

Run a Python Bot as a systemd Service

Running a Python bot through systemd provides:

The following example assumes the application is located in:

/home/Bot

Create a Python virtual environment

Open the application directory:

cd /home/Bot

Create the virtual environment:

python3 -m venv venv

Activate it:

source venv/bin/activate

Upgrade pip:

python -m pip install --upgrade pip

Install the required packages:

pip install -r requirements.txt

If the project does not yet have a requirements file:

pip freeze > requirements.txt

Create the Python application

For example:

nano /home/Bot/bot.py

Minimal test application:

import logging
import time

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(message)s",
)

logging.info("Bot started")

while True:
    time.sleep(60)

Recommended systemd service

Create the service file:

sudo nano /etc/systemd/system/bot.service

Add:

[Unit]
Description=Python Bot
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=bot
Group=bot
WorkingDirectory=/home/Bot
ExecStart=/home/Bot/venv/bin/python /home/Bot/bot.py

Restart=on-failure
RestartSec=5

Environment=PYTHONUNBUFFERED=1

NoNewPrivileges=true
PrivateTmp=true

[Install]
WantedBy=multi-user.target

This method starts the Python interpreter from the virtual environment directly. A separate start.sh script is normally unnecessary.

Replace User=bot and Group=bot with the actual unprivileged Linux account that owns and runs the application.


Reload systemd and start the service

sudo systemctl daemon-reload
sudo systemctl enable --now bot.service

Check its status:

sudo systemctl status bot.service

Display recent logs:

sudo journalctl -u bot.service -n 100 --no-pager

Follow logs in real time:

sudo journalctl -u bot.service -f

Restart the bot:

sudo systemctl restart bot.service

Stop it:

sudo systemctl stop bot.service

Disable automatic startup:

sudo systemctl disable bot.service

Alternative Startup Script

A startup script can still be useful when several commands must run before the application.

Create:

nano /home/Bot/start.sh

Add:

#!/usr/bin/env bash

set -euo pipefail

cd /home/Bot
exec /home/Bot/venv/bin/python /home/Bot/bot.py

Make it executable:

chmod +x /home/Bot/start.sh

Use it in the service:

ExecStart=/home/Bot/start.sh

Using exec ensures that systemd tracks the Python process correctly.


Raspberry Pi and GPIO

Temperature-Controlled Fan Script

The following script reads the Raspberry Pi CPU temperature and controls a fan through GPIO.

It uses two different thresholds:

This difference is called hysteresis. It prevents the fan from switching on and off repeatedly near one temperature.

The gpio command shown below is associated with older WiringPi-based installations. Modern Raspberry Pi systems may use raspi-gpio, pinctrl, libgpiod, or a Python GPIO library instead.

Create the script:

nano /usr/local/bin/fan-control.sh

Add:

#!/usr/bin/env bash

set -u

TEMP_FILE="/sys/class/thermal/thermal_zone0/temp"
GPIO_PIN=7
TURN_ON_TEMP=45000
TURN_OFF_TEMP=35000

if [[ ! -r "$TEMP_FILE" ]]; then
    echo "Temperature sensor file is unavailable: $TEMP_FILE" >&2
    exit 1
fi

temp=$(<"$TEMP_FILE")

if ! [[ "$temp" =~ ^[0-9]+$ ]]; then
    echo "Invalid temperature value: $temp" >&2
    exit 1
fi

echo "Current temperature: $((temp / 1000))°C"

gpio mode "$GPIO_PIN" out

if (( temp > TURN_ON_TEMP )); then
    gpio write "$GPIO_PIN" 1
    echo "Temperature is above 45°C. Cooling fan enabled."
elif (( temp < TURN_OFF_TEMP )); then
    gpio write "$GPIO_PIN" 0
    echo "Temperature is below 35°C. Cooling fan disabled."
else
    echo "Temperature is inside the hysteresis range. Fan state unchanged."
fi

Make it executable:

sudo chmod +x /usr/local/bin/fan-control.sh

Test it:

sudo /usr/local/bin/fan-control.sh

Run the script periodically with cron

Open the root crontab:

sudo crontab -e

Run the script once per minute:

* * * * * /usr/local/bin/fan-control.sh >> /var/log/fan-control.log 2>&1

For faster and more reliable control, create a continuously running service instead of invoking the script through cron.

Verify whether the GPIO number refers to WiringPi numbering, BCM numbering, or the physical header pin. Connecting a fan directly to a GPIO pin can damage the Raspberry Pi. Use a transistor or MOSFET driver and a flyback diode when controlling an inductive load.


Office Hardware

Log In to a Samsung Printer Web Interface

Many network-connected Samsung printers and multifunction devices provide a browser-based administration interface called SyncThru Web Service.

Open SyncThru Web Service

Find the printer's IP address and open it in a browser:

http://PRINTER-IP

Example:

http://192.168.1.50

Some devices may use HTTPS:

https://192.168.1.50

Common legacy credentials

Some older Samsung devices used the following defaults:

Username: admin
Password: sec00000

Some older models used:

Password: 1111

These credentials will not work when:

Change all default credentials before placing a printer on a trusted business network. The web interface should not be exposed directly to the Internet.

If the password is unknown, consult the device manual or follow the model-specific reset procedure.


Django and Web Development

Add an HTML Datalist to a Django Form

An HTML <datalist> provides autocomplete suggestions while still allowing the user to enter a custom value.

This is useful for fields such as:

A common mistake is to generate raw HTML inside the Django view or edit Django's files inside site-packages. Neither approach is necessary.

The cleaner solution is:

  1. query distinct values from the database;
  2. send them to the template;
  3. use a normal Django TextInput;
  4. add a list attribute pointing to a <datalist> element.

Example model

from django.conf import settings
from django.db import models


class AddInfo(models.Model):
    work_where = models.CharField(max_length=255)
    work_who = models.CharField(max_length=255)
    work_what = models.TextField(blank=True)
    work_minutes = models.PositiveIntegerField(default=0)
    work_user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.PROTECT,
    )

    def __str__(self) -> str:
        return f"{self.work_where}: {self.work_what[:50]}"

Configure the form widgets

Use TextInput for fields connected to a datalist:

from django import forms

from .models import AddInfo


class AddInfoForm(forms.ModelForm):
    class Meta:
        model = AddInfo

        fields = [
            "work_where",
            "work_who",
            "work_what",
            "work_minutes",
            "work_user",
        ]

        widgets = {
            "work_where": forms.TextInput(
                attrs={
                    "list": "work-where-options",
                    "autocomplete": "off",
                }
            ),
            "work_who": forms.TextInput(
                attrs={
                    "list": "work-who-options",
                    "autocomplete": "off",
                }
            ),
            "work_what": forms.Textarea(
                attrs={
                    "cols": 80,
                    "rows": 5,
                }
            ),
        }

        labels = {
            "work_where": "Place or office",
            "work_who": "Employee",
            "work_what": "Comment",
            "work_minutes": "Working time",
        }

The important part is:

attrs={"list": "work-where-options"}

Its value must match the id of the corresponding <datalist> element.


Load distinct suggestions in the view

from django.shortcuts import render

from .forms import AddInfoForm
from .models import AddInfo


def add_info(request):
    if request.method == "POST":
        form = AddInfoForm(request.POST)

        if form.is_valid():
            form.save()
            form = AddInfoForm()
    else:
        form = AddInfoForm()

    work_where_options = (
        AddInfo.objects
        .exclude(work_where="")
        .values_list("work_where", flat=True)
        .distinct()
        .order_by("work_where")
    )

    work_who_options = (
        AddInfo.objects
        .exclude(work_who="")
        .values_list("work_who", flat=True)
        .distinct()
        .order_by("work_who")
    )

    context = {
        "form": form,
        "work_where_options": work_where_options,
        "work_who_options": work_who_options,
    }

    return render(request, "reports/add_info.html", context)

Using distinct() allows the database to remove duplicate values.

There is no need to:


Render the form and datalists

<form method="post">
    {% csrf_token %}

    {{ form.as_p }}

    <button type="submit">Submit</button>
</form>

<datalist id="work-where-options">
    {% for value in work_where_options %}
        <option value="{{ value }}"></option>
    {% endfor %}
</datalist>

<datalist id="work-who-options">
    {% for value in work_who_options %}
        <option value="{{ value }}"></option>
    {% endfor %}
</datalist>

Django automatically escapes template values, which is safer than constructing raw HTML in the view.


Example with django-bootstrap

When the project uses a Bootstrap form package, the datalists remain the same:

{% load bootstrap5 %}

<form method="post">
    {% csrf_token %}

    {% bootstrap_form form %}

    <button type="submit" class="btn btn-primary">
        Submit
    </button>
</form>

<datalist id="work-where-options">
    {% for value in work_where_options %}
        <option value="{{ value }}"></option>
    {% endfor %}
</datalist>

<datalist id="work-who-options">
    {% for value in work_who_options %}
        <option value="{{ value }}"></option>
    {% endfor %}
</datalist>

Important Notes

Use a text input

A datalist works with:

<input type="text">

It does not provide the same behavior for a <textarea>.

Therefore, the Django widget must be:

forms.TextInput

and not:

forms.Textarea

Do not edit files in site-packages

Avoid modifying:

venv/lib/pythonX.X/site-packages/django/forms/templates/

Such changes:

Configure the list attribute through the form widget instead.

A datalist does not restrict values

Unlike a <select> element, a datalist only provides suggestions. The user can still type a value that is not in the list.

Use a model relation or custom validation when only predefined values should be allowed.


Compatibility Notes

The examples on this page cover several generations of operating systems and software.

Before applying a command:

  1. Check the operating system or RouterOS version.
  2. Create a backup.
  3. Test the change outside production when possible.
  4. Confirm interface names, paths, usernames, and service names.
  5. Do not paste commands blindly into a production environment.

Last updated: August 2026