mirror of
https://github.com/samjage/Uplink-Manager.git
synced 2026-06-06 00:40:42 +00:00
Removed MSI
Creating Release instead
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
from PyInstaller.utils.hooks import collect_all
|
||||
|
||||
datas = []
|
||||
binaries = []
|
||||
hiddenimports = []
|
||||
tmp_ret = collect_all('textual')
|
||||
datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2]
|
||||
|
||||
|
||||
a = Analysis(
|
||||
['uplink_manager.py'],
|
||||
pathex=[],
|
||||
binaries=binaries,
|
||||
datas=datas,
|
||||
hiddenimports=hiddenimports,
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
noarchive=False,
|
||||
optimize=0,
|
||||
)
|
||||
pyz = PYZ(a.pure)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.datas,
|
||||
[],
|
||||
name='Uplink Manager',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=True,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
uac_admin=True,
|
||||
icon=['uplink_manager.ico'],
|
||||
)
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,60 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Product Id="*" Name="Uplink Manager" Language="1033" Version="1.3.3.7" Manufacturer="samjage" UpgradeCode="993dff09-8800-4cc0-9f5f-2b88be50d0c9">
|
||||
|
||||
<Package InstallerVersion="500" Compressed="yes" InstallScope="perMachine" Platform="x64" />
|
||||
<MajorUpgrade DowngradeErrorMessage="A newer version of Uplink Manager is already installed." />
|
||||
<MediaTemplate />
|
||||
|
||||
<Icon Id="UplinkManagerIcon" SourceFile="uplink_manager.ico" />
|
||||
<Property Id="ARPPRODUCTICON" Value="UplinkManagerIcon" />
|
||||
|
||||
<Directory Id="TARGETDIR" Name="SourceDir">
|
||||
<Directory Id="ProgramFiles64Folder">
|
||||
<Directory Id="INSTALLFOLDER" Name="Uplink Manager" />
|
||||
</Directory>
|
||||
<!-- Add the Start Menu folder -->
|
||||
<Directory Id="ProgramMenuFolder">
|
||||
<Directory Id="ProgramMenuSubfolder" Name="Uplink Manager" />
|
||||
</Directory>
|
||||
</Directory>
|
||||
|
||||
<DirectoryRef Id="INSTALLFOLDER">
|
||||
<Component Id="cmpMainFiles" Guid="fae7711f-1ccd-49dc-a102-46a4768c67c7" Win64="yes">
|
||||
<File Id="fileUplinkExe" Source="dist\Uplink Manager.exe" KeyPath="yes" />
|
||||
<File Id="fileUplinkPs1" Source="uplink_manager_installer.ps1" />
|
||||
<File Id="fileUplinkIcon" Source="uplink_manager.ico" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<DirectoryRef Id="ProgramMenuSubfolder">
|
||||
<Component Id="cmpStartMenuShortcut" Guid="f73ad4c2-1e9a-40e3-b4f7-f41e518daf91"> <!-- Replace with a real GUID -->
|
||||
<Shortcut Id="StartMenuShortcut"
|
||||
Name="Uplink Manager"
|
||||
Target="[INSTALLFOLDER]Uplink Manager.exe"
|
||||
WorkingDirectory="INSTALLFOLDER"
|
||||
Icon="UplinkManagerIcon" />
|
||||
<RegistryValue Root="HKCU" Key="Software\Uplink Manager" Name="startmenu" Type="integer" Value="1" KeyPath="yes" />
|
||||
<RemoveFolder Id="RemoveProgramMenuSubfolder" Directory="ProgramMenuSubfolder" On="uninstall" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<Feature Id="MainFeature" Level="1">
|
||||
<ComponentRef Id="cmpMainFiles" />
|
||||
<ComponentRef Id="cmpStartMenuShortcut" />
|
||||
</Feature>
|
||||
|
||||
<CustomAction Id="RunUplinkInstaller"
|
||||
Directory="INSTALLFOLDER"
|
||||
ExeCommand='[SystemFolder]WindowsPowerShell\v1.0\powershell.exe -WindowStyle Hidden -ExecutionPolicy Bypass -NoLogo -NoProfile -File "uplink_manager_installer.ps1"'
|
||||
Execute="deferred"
|
||||
Return="ignore"
|
||||
Impersonate="no"
|
||||
HideTarget="yes" />
|
||||
|
||||
<InstallExecuteSequence>
|
||||
<Custom Action="RunUplinkInstaller" After="InstallFiles">NOT REMOVE</Custom>
|
||||
</InstallExecuteSequence>
|
||||
|
||||
</Product>
|
||||
</Wix>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,175 @@
|
||||
|
||||
This file lists modules PyInstaller was not able to find. This does not
|
||||
necessarily mean these modules are required for running your program. Both
|
||||
Python's standard library and 3rd-party Python packages often conditionally
|
||||
import optional modules, some of which may be available only on certain
|
||||
platforms.
|
||||
|
||||
Types of import:
|
||||
* top-level: imported at the top-level - look at these first
|
||||
* conditional: imported within an if-statement
|
||||
* delayed: imported within a function
|
||||
* optional: imported within a try-except-statement
|
||||
|
||||
IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
|
||||
tracking down the missing module yourself. Thanks!
|
||||
|
||||
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
missing module named 'collections.abc' - imported by traceback (top-level), typing (top-level), inspect (top-level), logging (top-level), importlib.resources.readers (top-level), selectors (top-level), tracemalloc (top-level), IPython.core.interactiveshell (top-level), IPython.external.pickleshare (optional), typing_extensions (top-level), asyncio.base_events (top-level), http.client (top-level), asyncio.coroutines (top-level), configparser (top-level), IPython.lib.display (top-level), IPython.utils.data (top-level), IPython.utils._process_common (top-level), IPython.utils.decorators (top-level), IPython.utils.openpy (top-level), IPython.utils.text (top-level), IPython.utils.tokenutil (top-level), IPython.core.ultratb (top-level), IPython.core.doctb (top-level), IPython.core.tbtools (top-level), wcwidth.grapheme (conditional), wcwidth.wcwidth (conditional), IPython.core.completer (top-level), IPython.core.guarded_eval (top-level), parso.python.tree (top-level), IPython.terminal.shortcuts (top-level), IPython.terminal.shortcuts.auto_suggest (top-level), IPython.terminal.shortcuts.filters (top-level), IPython.core.history (top-level), sqlite3.dbapi2 (top-level), IPython.terminal.pt_inputhooks (top-level), _pyrepl.types (top-level), _pyrepl.readline (top-level), tornado.gen (top-level), jupyter_core.utils (top-level), jupyter_client.jsonutil (top-level), jupyter_core.paths (top-level), platformdirs.api (conditional), platformdirs.windows (conditional), platformdirs.macos (conditional), platformdirs.unix (conditional), jupyter_client.localinterfaces (top-level), jupyter_client.utils (top-level), ipykernel.iostream (top-level), ipykernel.kernelbase (top-level), ipykernel.utils (top-level), setuptools (top-level), setuptools._distutils.filelist (top-level), setuptools._distutils.util (top-level), setuptools._vendor.jaraco.functools (top-level), setuptools._vendor.more_itertools.more (top-level), setuptools._distutils._modified (top-level), setuptools._distutils.compat (top-level), setuptools._distutils.spawn (top-level), setuptools._distutils.compilers.C.base (top-level), setuptools._distutils.fancy_getopt (top-level), setuptools._reqs (top-level), setuptools._vendor.jaraco.context (top-level), setuptools.discovery (top-level), setuptools.dist (top-level), setuptools._distutils.command.bdist (top-level), setuptools._distutils.core (top-level), setuptools._distutils.cmd (top-level), setuptools._distutils.dist (top-level), setuptools._distutils.extension (top-level), setuptools.config.setupcfg (top-level), setuptools.config.expand (top-level), setuptools.config.pyprojecttoml (top-level), setuptools.config._apply_pyprojecttoml (top-level), setuptools.extension (top-level), tomllib._parser (top-level), setuptools._vendor.tomli._parser (conditional), setuptools.wheel (top-level), setuptools.command.egg_info (top-level), setuptools.command.bdist_egg (top-level), setuptools.command.sdist (top-level), setuptools._distutils.command.build (top-level), setuptools._distutils.command.sdist (top-level), setuptools.glob (top-level), setuptools.command._requirestxt (top-level), setuptools.command.bdist_wheel (top-level), setuptools._vendor.importlib_metadata (top-level), setuptools._vendor.importlib_metadata._meta (top-level), markdown_it.main (top-level), markdown_it.ruler (top-level), markdown_it.utils (top-level), markdown_it.token (top-level), markdown_it.common.normalize_url (top-level), mdurl._decode (top-level), mdurl._encode (top-level), markdown_it._punycode (top-level), markdown_it.parser_block (top-level), markdown_it.parser_core (top-level), markdown_it.parser_inline (top-level), markdown_it.renderer (top-level), rich.scope (top-level), setuptools._distutils.command.build_ext (top-level), setuptools._distutils.compilers.C.msvc (top-level)
|
||||
missing module named posix - imported by os (conditional, optional), posixpath (optional), shutil (conditional), importlib._bootstrap_external (conditional), _pyrepl.unix_console (delayed, optional)
|
||||
missing module named resource - imported by posix (top-level), IPython.utils.timing (optional)
|
||||
missing module named pwd - imported by posixpath (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib._local (optional), subprocess (delayed, conditional, optional), getpass (delayed, optional), netrc (delayed, optional), http.server (delayed, optional), psutil (optional), setuptools._distutils.util (delayed, conditional, optional), setuptools._vendor.backports.tarfile (optional), setuptools._distutils.archive_util (optional)
|
||||
missing module named grp - imported by shutil (delayed, optional), tarfile (optional), pathlib._local (optional), subprocess (delayed, conditional, optional), setuptools._vendor.backports.tarfile (optional), setuptools._distutils.archive_util (optional)
|
||||
missing module named _posixshmem - imported by multiprocessing.resource_tracker (conditional), multiprocessing.shared_memory (conditional)
|
||||
missing module named multiprocessing.set_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||
missing module named multiprocessing.get_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||
missing module named _posixsubprocess - imported by subprocess (conditional), multiprocessing.util (delayed)
|
||||
missing module named multiprocessing.get_context - imported by multiprocessing (top-level), multiprocessing.pool (top-level), multiprocessing.managers (top-level), multiprocessing.sharedctypes (top-level)
|
||||
missing module named multiprocessing.TimeoutError - imported by multiprocessing (top-level), multiprocessing.pool (top-level)
|
||||
missing module named _scproxy - imported by urllib.request (conditional)
|
||||
missing module named termios - imported by getpass (optional), tty (top-level), IPython.core.page (delayed, optional), _pyrepl.pager (delayed, optional), prompt_toolkit.input.vt100 (top-level), _pyrepl.unix_console (top-level), _pyrepl.fancy_termios (top-level), _pyrepl.unix_eventqueue (top-level), textual.drivers.linux_driver (top-level), textual.drivers.linux_inline_driver (top-level)
|
||||
missing module named multiprocessing.BufferTooShort - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||
missing module named multiprocessing.AuthenticationError - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||
missing module named multiprocessing.Process - imported by multiprocessing (top-level), jupyter_client.ssh.tunnel (top-level)
|
||||
missing module named asyncio.DefaultEventLoopPolicy - imported by asyncio (delayed, conditional), asyncio.events (delayed, conditional)
|
||||
missing module named annotationlib - imported by typing_extensions (conditional), IPython.lib.pretty (conditional)
|
||||
missing module named _typeshed - imported by prompt_toolkit.eventloop.inputhook (conditional), setuptools._distutils.dist (conditional), setuptools.command.bdist_egg (conditional), setuptools.glob (conditional), setuptools._vendor.wheel.wheelfile (conditional), setuptools.compat.py311 (conditional), textual._node_list (conditional), textual.dom (conditional)
|
||||
missing module named vms_lib - imported by platform (delayed, optional)
|
||||
missing module named 'java.lang' - imported by platform (delayed, optional)
|
||||
missing module named java - imported by platform (delayed)
|
||||
missing module named usercustomize - imported by site (delayed, optional)
|
||||
missing module named sitecustomize - imported by site (delayed, optional)
|
||||
missing module named _curses - imported by curses (top-level), curses.has_key (top-level), _pyrepl.curses (optional)
|
||||
missing module named fcntl - imported by subprocess (optional), pty (delayed, optional), _pyrepl.unix_console (top-level)
|
||||
missing module named readline - imported by cmd (delayed, conditional, optional), code (delayed, conditional, optional), pdb (delayed, conditional, optional), rlcompleter (optional), pstats (conditional, optional), site (delayed, optional), sqlite3.__main__ (delayed, conditional, optional)
|
||||
missing module named _manylinux - imported by packaging._manylinux (delayed, optional), setuptools._vendor.packaging._manylinux (delayed, optional)
|
||||
missing module named importlib_resources - imported by setuptools._vendor.jaraco.text (optional)
|
||||
missing module named trove_classifiers - imported by setuptools.config._validate_pyproject.formats (optional)
|
||||
missing module named pyimod02_importers - imported by C:\Users\Admin\AppData\Local\Programs\Python\Python313\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py (delayed)
|
||||
missing module named sip - imported by IPython.external.qt_loaders (delayed, optional)
|
||||
missing module named argcomplete - imported by traitlets.config.loader (delayed, optional), traitlets.config.argcomplete_config (optional), IPython.core.tips (optional)
|
||||
missing module named traitlets.config.Application - imported by traitlets.config (delayed, conditional), traitlets.log (delayed, conditional), ipykernel.kernelspec (top-level)
|
||||
missing module named pygments.formatters.LatexFormatter - imported by pygments.formatters (delayed), IPython.lib.display (delayed)
|
||||
missing module named pygments.formatters.HtmlFormatter - imported by pygments.formatters (delayed), IPython.lib.display (delayed), IPython.core.oinspect (top-level), stack_data.core (delayed)
|
||||
missing module named pygments.lexers.PrologLexer - imported by pygments.lexers (top-level), pygments.lexers.cplint (top-level)
|
||||
missing module named pygments.lexers.PythonLexer - imported by pygments.lexers (top-level), IPython.core.oinspect (top-level)
|
||||
missing module named _winreg - imported by pygments.formatters.img (optional)
|
||||
missing module named PIL - imported by matplotlib_inline.config (delayed, optional), pygments.formatters.img (optional)
|
||||
missing module named ctags - imported by pygments.formatters.html (optional)
|
||||
missing module named chardet - imported by pygments.lexer (delayed, conditional, optional)
|
||||
missing module named pexpect - imported by IPython.utils._process_posix (delayed, conditional), jupyter_client.ssh.tunnel (optional)
|
||||
missing module named System - imported by IPython.utils._process_cli (top-level)
|
||||
missing module named clr - imported by IPython.utils._process_cli (top-level)
|
||||
missing module named 'yapf.yapflib' - imported by IPython.terminal.interactiveshell (delayed)
|
||||
missing module named yapf - imported by IPython.terminal.interactiveshell (delayed)
|
||||
missing module named black - imported by IPython.terminal.interactiveshell (delayed)
|
||||
missing module named jupyter_ai - imported by IPython.terminal.shortcuts.auto_suggest (delayed, optional)
|
||||
missing module named jupyter_ai_magics - imported by IPython.terminal.shortcuts.auto_suggest (delayed, optional)
|
||||
missing module named prompt_toolkit.filters.vi_mode - imported by prompt_toolkit.filters (top-level), prompt_toolkit.document (top-level), prompt_toolkit.widgets.toolbars (top-level), prompt_toolkit.key_binding.bindings.page_navigation (top-level), IPython.terminal.shortcuts.filters (top-level)
|
||||
missing module named prompt_toolkit.filters.control_is_searchable - imported by prompt_toolkit.filters (top-level), prompt_toolkit.key_binding.bindings.search (top-level)
|
||||
missing module named prompt_toolkit.filters.vi_insert_mode - imported by prompt_toolkit.filters (top-level), prompt_toolkit.layout.containers (top-level), prompt_toolkit.key_binding.bindings.basic (top-level), IPython.terminal.shortcuts.filters (top-level)
|
||||
missing module named prompt_toolkit.filters.emacs_insert_mode - imported by prompt_toolkit.filters (top-level), prompt_toolkit.layout.containers (top-level), prompt_toolkit.key_binding.bindings.basic (top-level), prompt_toolkit.key_binding.bindings.emacs (top-level), IPython.terminal.shortcuts.filters (top-level)
|
||||
missing module named prompt_toolkit.filters.is_done - imported by prompt_toolkit.filters (top-level), prompt_toolkit.shortcuts.choice_input (top-level), prompt_toolkit.widgets.base (top-level), prompt_toolkit.shortcuts.progress_bar.base (top-level), prompt_toolkit.shortcuts.prompt (top-level), prompt_toolkit.layout.menus (top-level)
|
||||
missing module named prompt_toolkit.filters.has_completions - imported by prompt_toolkit.filters (top-level), prompt_toolkit.widgets.toolbars (top-level), prompt_toolkit.widgets.dialogs (top-level), prompt_toolkit.layout.menus (top-level), IPython.terminal.shortcuts.filters (top-level)
|
||||
missing module named prompt_toolkit.filters.is_searching - imported by prompt_toolkit.filters (top-level), prompt_toolkit.key_binding.bindings.vi (top-level), prompt_toolkit.search (top-level), prompt_toolkit.key_binding.bindings.search (top-level)
|
||||
missing module named prompt_toolkit.filters.is_read_only - imported by prompt_toolkit.filters (top-level), prompt_toolkit.key_binding.bindings.vi (top-level), prompt_toolkit.key_binding.bindings.emacs (top-level)
|
||||
missing module named prompt_toolkit.filters.has_arg - imported by prompt_toolkit.filters (top-level), prompt_toolkit.key_binding.bindings.vi (top-level), prompt_toolkit.widgets.toolbars (top-level), prompt_toolkit.key_binding.bindings.emacs (top-level), prompt_toolkit.shortcuts.prompt (top-level)
|
||||
missing module named prompt_toolkit.filters.vi_search_direction_reversed - imported by prompt_toolkit.filters (top-level), prompt_toolkit.key_binding.bindings.emacs (top-level)
|
||||
missing module named prompt_toolkit.filters.shift_selection_mode - imported by prompt_toolkit.filters (top-level), prompt_toolkit.key_binding.bindings.emacs (top-level)
|
||||
missing module named prompt_toolkit.filters.is_multiline - imported by prompt_toolkit.filters (top-level), prompt_toolkit.key_binding.bindings.basic (top-level), prompt_toolkit.key_binding.bindings.emacs (top-level)
|
||||
missing module named prompt_toolkit.filters.in_paste_mode - imported by prompt_toolkit.filters (top-level), prompt_toolkit.key_binding.bindings.basic (top-level), prompt_toolkit.key_binding.bindings.emacs (top-level)
|
||||
missing module named prompt_toolkit.filters.has_selection - imported by prompt_toolkit.filters (top-level), prompt_toolkit.key_binding.bindings.basic (top-level), prompt_toolkit.key_binding.bindings.emacs (top-level), prompt_toolkit.key_binding.bindings.open_in_editor (top-level), IPython.terminal.shortcuts.filters (top-level)
|
||||
missing module named prompt_toolkit.filters.emacs_mode - imported by prompt_toolkit.filters (top-level), prompt_toolkit.widgets.toolbars (top-level), prompt_toolkit.key_binding.bindings.emacs (top-level), prompt_toolkit.key_binding.bindings.auto_suggest (top-level), prompt_toolkit.key_binding.bindings.open_in_editor (top-level), prompt_toolkit.key_binding.bindings.page_navigation (top-level)
|
||||
missing module named prompt_toolkit.filters.buffer_has_focus - imported by prompt_toolkit.filters (top-level), prompt_toolkit.key_binding.defaults (top-level), prompt_toolkit.key_binding.bindings.page_navigation (top-level)
|
||||
missing module named prompt_toolkit.filters.vi_navigation_mode - imported by prompt_toolkit.filters (top-level), prompt_toolkit.widgets.toolbars (top-level), prompt_toolkit.key_binding.bindings.open_in_editor (top-level)
|
||||
missing module named prompt_toolkit.filters.has_validation_error - imported by prompt_toolkit.filters (top-level), prompt_toolkit.widgets.toolbars (top-level)
|
||||
missing module named prompt_toolkit.filters.renderer_height_is_known - imported by prompt_toolkit.filters (top-level), prompt_toolkit.shortcuts.choice_input (top-level), prompt_toolkit.shortcuts.progress_bar.base (top-level), prompt_toolkit.shortcuts.prompt (top-level)
|
||||
missing module named prompt_toolkit.filters.has_focus - imported by prompt_toolkit.filters (top-level), prompt_toolkit.widgets.base (top-level), prompt_toolkit.widgets.toolbars (top-level), prompt_toolkit.widgets.dialogs (top-level), prompt_toolkit.shortcuts.prompt (top-level), IPython.terminal.shortcuts.filters (top-level)
|
||||
missing module named win32clipboard - imported by IPython.lib.clipboard (delayed, optional)
|
||||
missing module named prompt_toolkit.filters.vi_insert_multiple_mode - imported by prompt_toolkit.filters (top-level), prompt_toolkit.layout.processors (top-level)
|
||||
missing module named trio - imported by IPython.core.async_helpers (delayed), ipykernel.trio_runner (top-level)
|
||||
missing module named curio - imported by IPython.core.async_helpers (delayed)
|
||||
missing module named numpy - imported by IPython.lib.display (delayed), IPython.core.formatters (delayed, conditional), IPython.core.magics.namespace (delayed, conditional, optional)
|
||||
missing module named 'nbformat.sign' - imported by IPython.core.magics.basic (delayed)
|
||||
missing module named nbformat - imported by IPython.core.magics.basic (delayed), IPython.core.interactiveshell (delayed, conditional)
|
||||
missing module named sqlite3.OperationalError - imported by sqlite3 (optional), IPython.core.history (optional)
|
||||
missing module named sqlite3.DatabaseError - imported by sqlite3 (optional), IPython.core.history (optional)
|
||||
missing module named 'IPython.config' - imported by IPython.core.history (conditional)
|
||||
missing module named pytest - imported by executing._pytest_utils (delayed, optional)
|
||||
missing module named 'astroid.node_classes' - imported by asttokens.astroid_compat (optional)
|
||||
missing module named 'astroid.nodes' - imported by asttokens.astroid_compat (optional), asttokens.util (optional)
|
||||
missing module named astroid - imported by asttokens.astroid_compat (optional)
|
||||
missing module named numpydoc - imported by jedi.inference.docstrings (delayed)
|
||||
missing module named pkg_resources - imported by jedi.plugins.pytest (delayed, conditional)
|
||||
missing module named win32evtlog - imported by logging.handlers (delayed, optional)
|
||||
missing module named win32evtlogutil - imported by logging.handlers (delayed, optional)
|
||||
missing module named netifaces - imported by jupyter_client.localinterfaces (delayed)
|
||||
missing module named msgpack - imported by jupyter_client.session (optional)
|
||||
missing module named orjson - imported by jupyter_client.session (optional)
|
||||
missing module named six.moves.range - imported by six.moves (top-level), dateutil.rrule (top-level)
|
||||
runtime module named six.moves - imported by dateutil.tz.tz (top-level), dateutil.tz._factories (top-level), dateutil.tz.win (top-level), dateutil.rrule (top-level)
|
||||
missing module named StringIO - imported by six (conditional)
|
||||
missing module named dateutil.tz.tzfile - imported by dateutil.tz (top-level), dateutil.zoneinfo (top-level)
|
||||
missing module named 'cython.cimports' - imported by zmq.backend.cython._zmq (top-level)
|
||||
missing module named cython - imported by zmq.backend.cython._zmq (top-level)
|
||||
missing module named gevent - imported by zmq.green.core (top-level), zmq.green.poll (top-level)
|
||||
missing module named 'gevent.core' - imported by zmq.green.core (delayed, optional)
|
||||
missing module named 'gevent.hub' - imported by zmq.green.core (top-level)
|
||||
missing module named 'gevent.event' - imported by zmq.green.core (top-level)
|
||||
missing module named zmq.backend.zmq_version_info - imported by zmq.backend (top-level), zmq.sugar.version (top-level)
|
||||
missing module named zmq.backend.Frame - imported by zmq.backend (top-level), zmq.sugar.frame (top-level), zmq.sugar.tracker (top-level)
|
||||
missing module named cffi - imported by zmq.utils.interop (delayed, optional)
|
||||
missing module named zmq.backend.Socket - imported by zmq.backend (top-level), zmq.sugar.socket (top-level)
|
||||
missing module named zmq.backend.zmq_poll - imported by zmq.backend (top-level), zmq.sugar.poll (top-level)
|
||||
missing module named pyczmq - imported by zmq.sugar.context (delayed)
|
||||
missing module named zmq.backend.Context - imported by zmq.backend (top-level), zmq.sugar.context (top-level)
|
||||
missing module named zmq.backend.proxy - imported by zmq.backend (top-level), zmq.sugar (top-level)
|
||||
missing module named zmq.ZMQError - imported by zmq (delayed, optional), zmq.sugar.attrsettr (delayed, optional)
|
||||
missing module named zmq.backend.zmq_errno - imported by zmq.backend (delayed), zmq.error (delayed, conditional)
|
||||
missing module named zmq.backend.strerror - imported by zmq.backend (delayed), zmq.error (delayed)
|
||||
missing module named zmq.zmq_version_info - imported by zmq (delayed, conditional), zmq.error (delayed, conditional)
|
||||
missing module named zmq.zmq_version - imported by zmq (delayed, conditional), zmq.error (delayed, conditional)
|
||||
missing module named _subprocess - imported by jupyter_client.launcher (delayed, conditional, optional), ipykernel.parentpoller (delayed, optional)
|
||||
missing module named paramiko - imported by jupyter_client.ssh.tunnel (optional)
|
||||
missing module named win32security - imported by jupyter_core.paths (delayed)
|
||||
missing module named ntsecuritycon - imported by jupyter_core.paths (delayed)
|
||||
missing module named win32api - imported by jupyter_core.paths (delayed, optional)
|
||||
missing module named jnius - imported by platformdirs.android (delayed, conditional, optional)
|
||||
missing module named android - imported by platformdirs.android (delayed, conditional, optional)
|
||||
missing module named ipykernel.get_connection_info - imported by ipykernel (top-level), ipykernel.zmqshell (top-level)
|
||||
missing module named ipykernel.get_connection_file - imported by ipykernel (top-level), ipykernel.zmqshell (top-level)
|
||||
missing module named ipykernel.connect_qtconsole - imported by ipykernel (top-level), ipykernel.zmqshell (top-level)
|
||||
missing module named PySide6 - imported by ipykernel.eventloops (delayed, conditional, optional)
|
||||
missing module named PyQt6 - imported by ipykernel.eventloops (delayed, conditional, optional)
|
||||
missing module named PySide2 - imported by ipykernel.eventloops (delayed, conditional, optional)
|
||||
missing module named PyQt5 - imported by ipykernel.eventloops (delayed, conditional, optional)
|
||||
missing module named 'gi.repository' - imported by ipykernel.gui.gtk3embed (top-level)
|
||||
missing module named gi - imported by ipykernel.gui.gtk3embed (top-level)
|
||||
missing module named gtk - imported by ipykernel.gui.gtkembed (top-level)
|
||||
missing module named gobject - imported by ipykernel.gui.gtkembed (top-level)
|
||||
missing module named wx - imported by ipykernel.eventloops (delayed), IPython.lib.guisupport (delayed)
|
||||
missing module named ipykernel.serialize - imported by ipykernel.ipkernel (delayed, optional)
|
||||
missing module named ipyparallel - imported by ipykernel.ipkernel (delayed, optional)
|
||||
missing module named appnope - imported by ipykernel.ipkernel (delayed, conditional)
|
||||
missing module named '_pydevd_bundle.pydevd_api' - imported by ipykernel.debugger (delayed)
|
||||
missing module named '_pydevd_bundle.pydevd_suspended_frames' - imported by ipykernel.debugger (optional)
|
||||
missing module named _pydevd_bundle - imported by debugpy._vendored.force_pydevd (top-level), debugpy.server.cli (top-level), ipykernel.debugger (optional)
|
||||
missing module named pydevd_file_utils - imported by debugpy.server.api (top-level)
|
||||
missing module named '_pydevd_bundle.pydevd_constants' - imported by debugpy.server.api (top-level)
|
||||
missing module named add_code_to_python_process - imported by debugpy.server.cli (delayed, optional)
|
||||
missing module named pydevd - imported by debugpy._vendored.force_pydevd (top-level), debugpy.server.api (top-level), debugpy.server.cli (top-level)
|
||||
missing module named 'matplotlib.figure' - imported by matplotlib_inline.backend_inline (top-level)
|
||||
missing module named 'matplotlib.backends' - imported by matplotlib_inline.backend_inline (top-level)
|
||||
missing module named 'matplotlib._pylab_helpers' - imported by matplotlib_inline.backend_inline (top-level)
|
||||
missing module named matplotlib - imported by matplotlib_inline.backend_inline (top-level)
|
||||
missing module named docrepr - imported by IPython.core.interactiveshell (optional)
|
||||
missing module named cPickle - imported by IPython.external.pickleshare (optional)
|
||||
missing module named ipywidgets - imported by rich.live (delayed, conditional, optional)
|
||||
missing module named attr - imported by rich.pretty (optional)
|
||||
missing module named tree_sitter - imported by textual._tree_sitter (optional), textual.document._document (conditional), textual.document._syntax_aware_document (optional), textual.widgets._text_area (conditional)
|
||||
missing module named textual_speedups - imported by textual.geometry (conditional, optional)
|
||||
missing module named httpx - imported by textual.demo.home (optional)
|
||||
missing module named 'textual_dev.redirect_output' - imported by textual.app (delayed, conditional, optional)
|
||||
missing module named 'textual_dev.client' - imported by textual.app (delayed, conditional, optional)
|
||||
missing module named textual_dev - imported by textual.app (conditional)
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,163 @@
|
||||
('C:\\Uplink Manager\\dist\\Uplink Manager.exe',
|
||||
True,
|
||||
False,
|
||||
False,
|
||||
['C:\\Uplink Manager\\uplink_manager.ico'],
|
||||
None,
|
||||
True,
|
||||
False,
|
||||
b'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\n<assembly xmlns='
|
||||
b'"urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">\n <trustInfo x'
|
||||
b'mlns="urn:schemas-microsoft-com:asm.v3">\n <security>\n <requested'
|
||||
b'Privileges>\n <requestedExecutionLevel level="requireAdministrator'
|
||||
b'" uiAccess="false"/>\n </requestedPrivileges>\n </security>\n </tr'
|
||||
b'ustInfo>\n <compatibility xmlns="urn:schemas-microsoft-com:compatibility'
|
||||
b'.v1">\n <application>\n <supportedOS Id="{e2011457-1546-43c5-a5fe-'
|
||||
b'008deee3d3f0}"/>\n <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a244022'
|
||||
b'5f93a}"/>\n <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"'
|
||||
b'/>\n <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>\n '
|
||||
b' <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>\n </appli'
|
||||
b'cation>\n </compatibility>\n <application xmlns="urn:schemas-microsoft-c'
|
||||
b'om:asm.v3">\n <windowsSettings>\n <longPathAware xmlns="http://sch'
|
||||
b'emas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>\n </'
|
||||
b'windowsSettings>\n </application>\n <dependency>\n <dependentAssembly>'
|
||||
b'\n <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Con'
|
||||
b'trols" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b6414'
|
||||
b'4ccf1df" language="*"/>\n </dependentAssembly>\n </dependency>\n</assem'
|
||||
b'bly>',
|
||||
True,
|
||||
False,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
'C:\\Uplink Manager\\build\\uplink_manager\\Uplink Manager.pkg',
|
||||
[('pyi-contents-directory _internal', '', 'OPTION'),
|
||||
('PYZ-00.pyz',
|
||||
'C:\\Uplink Manager\\build\\uplink_manager\\PYZ-00.pyz',
|
||||
'PYZ'),
|
||||
('struct',
|
||||
'C:\\Uplink Manager\\build\\uplink_manager\\localpycs\\struct.pyc',
|
||||
'PYMODULE'),
|
||||
('pyimod01_archive',
|
||||
'C:\\Uplink Manager\\build\\uplink_manager\\localpycs\\pyimod01_archive.pyc',
|
||||
'PYMODULE'),
|
||||
('pyimod02_importers',
|
||||
'C:\\Uplink '
|
||||
'Manager\\build\\uplink_manager\\localpycs\\pyimod02_importers.pyc',
|
||||
'PYMODULE'),
|
||||
('pyimod03_ctypes',
|
||||
'C:\\Uplink Manager\\build\\uplink_manager\\localpycs\\pyimod03_ctypes.pyc',
|
||||
'PYMODULE'),
|
||||
('pyimod04_pywin32',
|
||||
'C:\\Uplink Manager\\build\\uplink_manager\\localpycs\\pyimod04_pywin32.pyc',
|
||||
'PYMODULE'),
|
||||
('pyiboot01_bootstrap',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\loader\\pyiboot01_bootstrap.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_inspect',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_inspect.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_pkgutil',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgutil.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_multiprocessing',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_multiprocessing.py',
|
||||
'PYSOURCE'),
|
||||
('uplink_manager', 'C:\\Uplink Manager\\uplink_manager.py', 'PYSOURCE'),
|
||||
('python313.dll',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\python313.dll',
|
||||
'BINARY'),
|
||||
('_multiprocessing.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_multiprocessing.pyd',
|
||||
'EXTENSION'),
|
||||
('pyexpat.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\pyexpat.pyd',
|
||||
'EXTENSION'),
|
||||
('_ssl.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_ssl.pyd',
|
||||
'EXTENSION'),
|
||||
('_hashlib.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_hashlib.pyd',
|
||||
'EXTENSION'),
|
||||
('unicodedata.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\unicodedata.pyd',
|
||||
'EXTENSION'),
|
||||
('_decimal.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_decimal.pyd',
|
||||
'EXTENSION'),
|
||||
('_socket.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_socket.pyd',
|
||||
'EXTENSION'),
|
||||
('select.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\select.pyd',
|
||||
'EXTENSION'),
|
||||
('_lzma.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_lzma.pyd',
|
||||
'EXTENSION'),
|
||||
('_bz2.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_bz2.pyd',
|
||||
'EXTENSION'),
|
||||
('_queue.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_queue.pyd',
|
||||
'EXTENSION'),
|
||||
('_ctypes.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_ctypes.pyd',
|
||||
'EXTENSION'),
|
||||
('_wmi.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_wmi.pyd',
|
||||
'EXTENSION'),
|
||||
('_uuid.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_uuid.pyd',
|
||||
'EXTENSION'),
|
||||
('_overlapped.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_overlapped.pyd',
|
||||
'EXTENSION'),
|
||||
('_asyncio.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_asyncio.pyd',
|
||||
'EXTENSION'),
|
||||
('VCRUNTIME140.dll',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140.dll',
|
||||
'BINARY'),
|
||||
('libcrypto-3.dll',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libcrypto-3.dll',
|
||||
'BINARY'),
|
||||
('libssl-3.dll',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libssl-3.dll',
|
||||
'BINARY'),
|
||||
('libffi-8.dll',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libffi-8.dll',
|
||||
'BINARY'),
|
||||
('VCRUNTIME140_1.dll',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140_1.dll',
|
||||
'BINARY'),
|
||||
('run_uplink.cmd', 'C:\\Uplink Manager\\run_uplink.cmd', 'DATA'),
|
||||
('run_uplink.ps1', 'C:\\Uplink Manager\\run_uplink.ps1', 'DATA'),
|
||||
('textual-8.1.1.dist-info\\licenses\\LICENSE',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\textual-8.1.1.dist-info\\licenses\\LICENSE',
|
||||
'DATA'),
|
||||
('textual-8.1.1.dist-info\\RECORD',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\textual-8.1.1.dist-info\\RECORD',
|
||||
'DATA'),
|
||||
('textual-8.1.1.dist-info\\METADATA',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\textual-8.1.1.dist-info\\METADATA',
|
||||
'DATA'),
|
||||
('textual-8.1.1.dist-info\\WHEEL',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\textual-8.1.1.dist-info\\WHEEL',
|
||||
'DATA'),
|
||||
('textual-8.1.1.dist-info\\INSTALLER',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\textual-8.1.1.dist-info\\INSTALLER',
|
||||
'DATA'),
|
||||
('textual-8.1.1.dist-info\\REQUESTED',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\textual-8.1.1.dist-info\\REQUESTED',
|
||||
'DATA'),
|
||||
('base_library.zip',
|
||||
'C:\\Uplink Manager\\build\\uplink_manager\\base_library.zip',
|
||||
'DATA')],
|
||||
[],
|
||||
False,
|
||||
False,
|
||||
1774455296,
|
||||
[('run.exe',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\bootloader\\Windows-64bit-intel\\run.exe',
|
||||
'EXECUTABLE')],
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\python313.dll')
|
||||
@@ -0,0 +1,140 @@
|
||||
('C:\\Uplink Manager\\build\\uplink_manager\\Uplink Manager.pkg',
|
||||
{'BINARY': True,
|
||||
'DATA': True,
|
||||
'EXECUTABLE': True,
|
||||
'EXTENSION': True,
|
||||
'PYMODULE': True,
|
||||
'PYSOURCE': True,
|
||||
'PYZ': False,
|
||||
'SPLASH': True,
|
||||
'SYMLINK': False},
|
||||
[('pyi-contents-directory _internal', '', 'OPTION'),
|
||||
('PYZ-00.pyz',
|
||||
'C:\\Uplink Manager\\build\\uplink_manager\\PYZ-00.pyz',
|
||||
'PYZ'),
|
||||
('struct',
|
||||
'C:\\Uplink Manager\\build\\uplink_manager\\localpycs\\struct.pyc',
|
||||
'PYMODULE'),
|
||||
('pyimod01_archive',
|
||||
'C:\\Uplink Manager\\build\\uplink_manager\\localpycs\\pyimod01_archive.pyc',
|
||||
'PYMODULE'),
|
||||
('pyimod02_importers',
|
||||
'C:\\Uplink '
|
||||
'Manager\\build\\uplink_manager\\localpycs\\pyimod02_importers.pyc',
|
||||
'PYMODULE'),
|
||||
('pyimod03_ctypes',
|
||||
'C:\\Uplink Manager\\build\\uplink_manager\\localpycs\\pyimod03_ctypes.pyc',
|
||||
'PYMODULE'),
|
||||
('pyimod04_pywin32',
|
||||
'C:\\Uplink Manager\\build\\uplink_manager\\localpycs\\pyimod04_pywin32.pyc',
|
||||
'PYMODULE'),
|
||||
('pyiboot01_bootstrap',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\loader\\pyiboot01_bootstrap.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_inspect',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_inspect.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_pkgutil',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_pkgutil.py',
|
||||
'PYSOURCE'),
|
||||
('pyi_rth_multiprocessing',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\PyInstaller\\hooks\\rthooks\\pyi_rth_multiprocessing.py',
|
||||
'PYSOURCE'),
|
||||
('uplink_manager', 'C:\\Uplink Manager\\uplink_manager.py', 'PYSOURCE'),
|
||||
('python313.dll',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\python313.dll',
|
||||
'BINARY'),
|
||||
('_multiprocessing.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_multiprocessing.pyd',
|
||||
'EXTENSION'),
|
||||
('pyexpat.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\pyexpat.pyd',
|
||||
'EXTENSION'),
|
||||
('_ssl.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_ssl.pyd',
|
||||
'EXTENSION'),
|
||||
('_hashlib.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_hashlib.pyd',
|
||||
'EXTENSION'),
|
||||
('unicodedata.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\unicodedata.pyd',
|
||||
'EXTENSION'),
|
||||
('_decimal.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_decimal.pyd',
|
||||
'EXTENSION'),
|
||||
('_socket.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_socket.pyd',
|
||||
'EXTENSION'),
|
||||
('select.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\select.pyd',
|
||||
'EXTENSION'),
|
||||
('_lzma.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_lzma.pyd',
|
||||
'EXTENSION'),
|
||||
('_bz2.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_bz2.pyd',
|
||||
'EXTENSION'),
|
||||
('_queue.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_queue.pyd',
|
||||
'EXTENSION'),
|
||||
('_ctypes.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_ctypes.pyd',
|
||||
'EXTENSION'),
|
||||
('_wmi.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_wmi.pyd',
|
||||
'EXTENSION'),
|
||||
('_uuid.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_uuid.pyd',
|
||||
'EXTENSION'),
|
||||
('_overlapped.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_overlapped.pyd',
|
||||
'EXTENSION'),
|
||||
('_asyncio.pyd',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\_asyncio.pyd',
|
||||
'EXTENSION'),
|
||||
('VCRUNTIME140.dll',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140.dll',
|
||||
'BINARY'),
|
||||
('libcrypto-3.dll',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libcrypto-3.dll',
|
||||
'BINARY'),
|
||||
('libssl-3.dll',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libssl-3.dll',
|
||||
'BINARY'),
|
||||
('libffi-8.dll',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\DLLs\\libffi-8.dll',
|
||||
'BINARY'),
|
||||
('VCRUNTIME140_1.dll',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\VCRUNTIME140_1.dll',
|
||||
'BINARY'),
|
||||
('run_uplink.cmd', 'C:\\Uplink Manager\\run_uplink.cmd', 'DATA'),
|
||||
('run_uplink.ps1', 'C:\\Uplink Manager\\run_uplink.ps1', 'DATA'),
|
||||
('textual-8.1.1.dist-info\\licenses\\LICENSE',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\textual-8.1.1.dist-info\\licenses\\LICENSE',
|
||||
'DATA'),
|
||||
('textual-8.1.1.dist-info\\RECORD',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\textual-8.1.1.dist-info\\RECORD',
|
||||
'DATA'),
|
||||
('textual-8.1.1.dist-info\\METADATA',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\textual-8.1.1.dist-info\\METADATA',
|
||||
'DATA'),
|
||||
('textual-8.1.1.dist-info\\WHEEL',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\textual-8.1.1.dist-info\\WHEEL',
|
||||
'DATA'),
|
||||
('textual-8.1.1.dist-info\\INSTALLER',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\textual-8.1.1.dist-info\\INSTALLER',
|
||||
'DATA'),
|
||||
('textual-8.1.1.dist-info\\REQUESTED',
|
||||
'C:\\Users\\Admin\\AppData\\Local\\Programs\\Python\\Python313\\Lib\\site-packages\\textual-8.1.1.dist-info\\REQUESTED',
|
||||
'DATA'),
|
||||
('base_library.zip',
|
||||
'C:\\Uplink Manager\\build\\uplink_manager\\base_library.zip',
|
||||
'DATA')],
|
||||
'python313.dll',
|
||||
False,
|
||||
False,
|
||||
False,
|
||||
[],
|
||||
None,
|
||||
None,
|
||||
None)
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,58 @@
|
||||
|
||||
This file lists modules PyInstaller was not able to find. This does not
|
||||
necessarily mean these modules are required for running your program. Both
|
||||
Python's standard library and 3rd-party Python packages often conditionally
|
||||
import optional modules, some of which may be available only on certain
|
||||
platforms.
|
||||
|
||||
Types of import:
|
||||
* top-level: imported at the top-level - look at these first
|
||||
* conditional: imported within an if-statement
|
||||
* delayed: imported within a function
|
||||
* optional: imported within a try-except-statement
|
||||
|
||||
IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for
|
||||
tracking down the missing module yourself. Thanks!
|
||||
|
||||
missing module named _posixshmem - imported by multiprocessing.resource_tracker (conditional), multiprocessing.shared_memory (conditional)
|
||||
missing module named _scproxy - imported by urllib.request (conditional)
|
||||
missing module named termios - imported by getpass (optional), tty (top-level), _pyrepl.pager (delayed, optional), textual.drivers.linux_driver (top-level), textual.drivers.linux_inline_driver (top-level)
|
||||
missing module named pwd - imported by posixpath (delayed, conditional, optional), shutil (delayed, optional), tarfile (optional), pathlib._local (optional), subprocess (delayed, conditional, optional), getpass (delayed, optional), http.server (delayed, optional), netrc (delayed, optional)
|
||||
missing module named 'collections.abc' - imported by traceback (top-level), typing (top-level), inspect (top-level), logging (top-level), importlib.resources.readers (top-level), selectors (top-level), tracemalloc (top-level), configparser (top-level), markdown_it.main (top-level), markdown_it.ruler (top-level), markdown_it.utils (top-level), typing_extensions (top-level), asyncio.base_events (top-level), http.client (top-level), asyncio.coroutines (top-level), markdown_it.token (top-level), markdown_it.common.normalize_url (top-level), mdurl._decode (top-level), mdurl._encode (top-level), markdown_it._punycode (top-level), markdown_it.parser_block (top-level), markdown_it.parser_core (top-level), markdown_it.parser_inline (top-level), markdown_it.renderer (top-level), rich.scope (top-level), platformdirs.api (conditional), platformdirs.windows (conditional), platformdirs.macos (conditional), platformdirs.unix (conditional)
|
||||
missing module named multiprocessing.BufferTooShort - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||
missing module named multiprocessing.AuthenticationError - imported by multiprocessing (top-level), multiprocessing.connection (top-level)
|
||||
missing module named _posixsubprocess - imported by subprocess (conditional), multiprocessing.util (delayed)
|
||||
missing module named _frozen_importlib_external - imported by importlib._bootstrap (delayed), importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
excluded module named _frozen_importlib - imported by importlib (optional), importlib.abc (optional), zipimport (top-level)
|
||||
missing module named grp - imported by shutil (delayed, optional), tarfile (optional), pathlib._local (optional), subprocess (delayed, conditional, optional)
|
||||
missing module named posix - imported by os (conditional, optional), posixpath (optional), shutil (conditional), importlib._bootstrap_external (conditional)
|
||||
missing module named resource - imported by posix (top-level)
|
||||
missing module named multiprocessing.get_context - imported by multiprocessing (top-level), multiprocessing.pool (top-level), multiprocessing.managers (top-level), multiprocessing.sharedctypes (top-level)
|
||||
missing module named multiprocessing.TimeoutError - imported by multiprocessing (top-level), multiprocessing.pool (top-level)
|
||||
missing module named multiprocessing.set_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||
missing module named multiprocessing.get_start_method - imported by multiprocessing (top-level), multiprocessing.spawn (top-level)
|
||||
missing module named pyimod02_importers - imported by C:\Users\Admin\AppData\Local\Programs\Python\Python313\Lib\site-packages\PyInstaller\hooks\rthooks\pyi_rth_pkgutil.py (delayed)
|
||||
missing module named IPython - imported by rich.jupyter (delayed, optional)
|
||||
missing module named 'IPython.core' - imported by rich.pretty (delayed, optional)
|
||||
missing module named attr - imported by rich.pretty (optional)
|
||||
missing module named pygments.lexers.PrologLexer - imported by pygments.lexers (top-level), pygments.lexers.cplint (top-level)
|
||||
missing module named _winreg - imported by pygments.formatters.img (optional)
|
||||
missing module named PIL - imported by pygments.formatters.img (optional)
|
||||
missing module named ctags - imported by pygments.formatters.html (optional)
|
||||
missing module named chardet - imported by pygments.lexer (delayed, conditional, optional)
|
||||
missing module named vms_lib - imported by platform (delayed, optional)
|
||||
missing module named 'java.lang' - imported by platform (delayed, optional)
|
||||
missing module named java - imported by platform (delayed)
|
||||
missing module named textual_speedups - imported by textual.geometry (conditional, optional)
|
||||
missing module named _typeshed - imported by textual._node_list (conditional), textual.dom (conditional)
|
||||
missing module named annotationlib - imported by typing_extensions (conditional)
|
||||
missing module named fcntl - imported by subprocess (optional), pty (delayed, optional)
|
||||
missing module named ipywidgets - imported by rich.live (delayed, conditional, optional)
|
||||
missing module named 'IPython.display' - imported by rich.live (delayed, conditional, optional)
|
||||
missing module named asyncio.DefaultEventLoopPolicy - imported by asyncio (delayed, conditional), asyncio.events (delayed, conditional)
|
||||
missing module named tree_sitter - imported by textual._tree_sitter (optional), textual.document._document (conditional), textual.document._syntax_aware_document (optional), textual.widgets._text_area (conditional)
|
||||
missing module named 'textual_dev.redirect_output' - imported by textual.app (delayed, conditional, optional)
|
||||
missing module named 'textual_dev.client' - imported by textual.app (delayed, conditional, optional)
|
||||
missing module named textual_dev - imported by textual.app (conditional)
|
||||
missing module named jnius - imported by platformdirs.android (delayed, conditional, optional)
|
||||
missing module named android - imported by platformdirs.android (delayed, conditional, optional)
|
||||
File diff suppressed because it is too large
Load Diff
Vendored
BIN
Binary file not shown.
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"test": {
|
||||
"gateway": "10.10.1.1",
|
||||
"subnet": "10.10.1.0/24",
|
||||
"uplink": "NAT Uplink",
|
||||
"dns_primary": "",
|
||||
"dns_secondary": "",
|
||||
"last_applied": "13:02:35"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
+1298
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,44 @@
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
block_cipher = None
|
||||
|
||||
a = Analysis(
|
||||
['uplink_manager.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[],
|
||||
hiddenimports=['textual'],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
win_no_prefer_redirects=False,
|
||||
win_private_assemblies=False,
|
||||
cipher=block_cipher,
|
||||
noarchive=False,
|
||||
)
|
||||
|
||||
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
[],
|
||||
name='Uplink Manager',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=False,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=True,
|
||||
disable_windowed_traceback=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
uac_admin=True,
|
||||
icon='uplink_manager.ico',
|
||||
)
|
||||
@@ -0,0 +1,862 @@
|
||||
# ──────────────────────────────────────────────────────────────────────────────
|
||||
# __ ______ __ _____ ____ __
|
||||
# / / / / __ \/ / / _/ | / / //_/
|
||||
# / / / / /_/ / / / // |/ / ,<
|
||||
# / /_/ / ____/ /____/ // /| / /| |
|
||||
# \____/_/ /_____/___/_/ |_/_/ |_|
|
||||
#
|
||||
#
|
||||
# __ ______ _ _____ ________________
|
||||
# / |/ / | / | / / | / ____/ ____/ __ \
|
||||
# / /|_/ / /| | / |/ / /| |/ / __/ __/ / /_/ /
|
||||
# / / / / ___ |/ /| / ___ / /_/ / /___/ _, _/
|
||||
# /_/ /_/_/ |_/_/ |_/_/ |_\____/_____/_/ |_|
|
||||
#
|
||||
# ──────────────────────────────────────────────────────────────────────────────
|
||||
# Uplink Manager Installer
|
||||
# Author: Sam Jage
|
||||
# ──────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
# ========== SELF‑ELEVATION BLOCK ==========
|
||||
$currentPrincipal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent())
|
||||
if (-not $currentPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
||||
Start-Process powershell.exe -Verb RunAs -ArgumentList "-WindowStyle Hidden -NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`""
|
||||
exit
|
||||
}
|
||||
# =========================================
|
||||
|
||||
# Force 64‑bit execution if running in 32‑bit mode
|
||||
if ($env:PROCESSOR_ARCHITECTURE -ne "AMD64") {
|
||||
$powershell = "$env:WINDIR\Sysnative\WindowsPowerShell\v1.0\powershell.exe"
|
||||
Start-Process $powershell -Verb RunAs -ArgumentList "-WindowStyle Hidden -NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`""
|
||||
exit
|
||||
}
|
||||
# =========================================
|
||||
|
||||
Add-Type -AssemblyName PresentationFramework
|
||||
Add-Type -AssemblyName PresentationCore
|
||||
Add-Type -AssemblyName WindowsBase
|
||||
Add-Type -AssemblyName System.Windows.Forms
|
||||
|
||||
# ── Version guard ─────────────────────────────────────────────────────────────
|
||||
if ($PSVersionTable.PSVersion.Major -lt 5) {
|
||||
[System.Windows.MessageBox]::Show(
|
||||
"This installer requires PowerShell 5.1 or higher.`n`nCurrent version: $($PSVersionTable.PSVersion)",
|
||||
"Incompatible PowerShell Version",
|
||||
[System.Windows.MessageBoxButton]::OK,
|
||||
[System.Windows.MessageBoxImage]::Error
|
||||
)
|
||||
exit 1
|
||||
}
|
||||
|
||||
# ── Colors ────────────────────────────────────────────────────────────────────
|
||||
$BG = "#252830"
|
||||
$SURFACE = "#2e3038"
|
||||
$PANEL = "#404450"
|
||||
$YELLOW = "#fabd2f"
|
||||
$GREEN = "#3d5c3f"
|
||||
$GREEN_LT = "#5a7d5c"
|
||||
$RED = "#fb4934"
|
||||
$TEXT = "#ebdbb2"
|
||||
$TEXT_MUTED = "#a89984"
|
||||
|
||||
# ── State ─────────────────────────────────────────────────────────────────────
|
||||
$script:SelectedInternet = $null
|
||||
$script:SelectedUplink = $null
|
||||
$script:CurrentPage = 0
|
||||
$script:NeedsReboot = $false
|
||||
$script:InstallDir = "C:\Program Files\Uplink Manager" # adjust if you use x86
|
||||
$script:SpinnerTimer = $null
|
||||
$script:SpinnerFrames = @("⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷")
|
||||
$script:SpinnerIndex = 0
|
||||
$script:ReqJob = $null
|
||||
$script:PrereqJob = $null
|
||||
|
||||
# ── Helpers (unchanged from your original) ──
|
||||
function Get-Vmxnet3Adapters {
|
||||
Get-NetAdapter | Where-Object { $_.InterfaceDescription -like "*vmxnet3*" -and $_.Status -eq "Up" } |
|
||||
Select-Object -ExpandProperty Name
|
||||
}
|
||||
|
||||
function Start-BtnSpinner {
|
||||
if ($script:SpinnerTimer) { $script:SpinnerTimer.Stop() }
|
||||
$script:SpinnerIndex = 0
|
||||
$script:SpinnerTimer = [System.Windows.Threading.DispatcherTimer]::new()
|
||||
$script:SpinnerTimer.Interval = [TimeSpan]::FromMilliseconds(100)
|
||||
$script:SpinnerTimer.Add_Tick({
|
||||
$script:SpinnerIndex = ($script:SpinnerIndex + 1) % $script:SpinnerFrames.Count
|
||||
$BtnNext.Content = $script:SpinnerFrames[$script:SpinnerIndex]
|
||||
})
|
||||
$BtnNext.IsEnabled = $false
|
||||
$script:SpinnerTimer.Start()
|
||||
}
|
||||
|
||||
function Stop-BtnSpinner {
|
||||
if ($script:SpinnerTimer) { $script:SpinnerTimer.Stop(); $script:SpinnerTimer = $null }
|
||||
$BtnNext.IsEnabled = $true
|
||||
$BtnNext.Content = "Next →"
|
||||
}
|
||||
|
||||
function Test-NatClass {
|
||||
try { Get-CimClass -Namespace root/StandardCimv2 -ClassName MSFT_NetNat -ErrorAction Stop | Out-Null; return $true }
|
||||
catch { return $false }
|
||||
}
|
||||
|
||||
# ── XAML UI ───────────────────────────────────────────────────────────────────
|
||||
[xml]$xaml = @"
|
||||
<Window
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="Uplink Manager Installer" Width="680" Height="580"
|
||||
WindowStartupLocation="CenterScreen" ResizeMode="NoResize"
|
||||
Background="$BG" FontFamily="Consolas">
|
||||
<Window.Resources>
|
||||
<Style TargetType="{x:Type Button}">
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type Button}">
|
||||
<Border x:Name="border" Background="{TemplateBinding Background}"
|
||||
BorderBrush="{TemplateBinding BorderBrush}"
|
||||
BorderThickness="{TemplateBinding BorderThickness}"
|
||||
Padding="{TemplateBinding Padding}">
|
||||
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="border" Property="Opacity" Value="0.75"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="border" Property="Opacity" Value="0.6"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
<Style x:Key="StepLabel" TargetType="TextBlock">
|
||||
<Setter Property="Foreground" Value="#a89984"/>
|
||||
<Setter Property="FontSize" Value="11"/>
|
||||
<Setter Property="Margin" Value="0,2,0,2"/>
|
||||
</Style>
|
||||
<Style x:Key="StatusDot" TargetType="Ellipse">
|
||||
<Setter Property="Width" Value="10"/>
|
||||
<Setter Property="Height" Value="10"/>
|
||||
<Setter Property="Margin" Value="0,0,8,0"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
<Grid Margin="0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="70"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="60"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Border Grid.Row="0" Background="#1a1c24">
|
||||
<StackPanel VerticalAlignment="Center" Margin="24,0,0,0">
|
||||
<TextBlock Text="Uplink Manager" FontSize="20" FontWeight="Bold" Foreground="$YELLOW" FontFamily="Consolas"/>
|
||||
<TextBlock Text="Virtual Machine Setup Installer for Windows 11" FontSize="11" Foreground="$TEXT_MUTED" Margin="0,2,0,0"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Grid Grid.Row="1" x:Name="PageContainer" Margin="0"/>
|
||||
<Border Grid.Row="2" Background="#1a1c24">
|
||||
<Grid Margin="24,0">
|
||||
<TextBlock x:Name="FooterStatus" VerticalAlignment="Center" Foreground="$TEXT_MUTED" FontSize="11" Text=""/>
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
|
||||
<Button x:Name="BtnBack" Content="← Back" Width="100" Height="32"
|
||||
Margin="0,0,8,0" Visibility="Collapsed"
|
||||
Background="$SURFACE" Foreground="$TEXT" BorderBrush="$PANEL"/>
|
||||
<Button x:Name="BtnNext" Content="Next →" Width="100" Height="32"
|
||||
Background="$GREEN" Foreground="$TEXT" BorderBrush="$GREEN" FontWeight="Bold"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Window>
|
||||
"@
|
||||
|
||||
$reader = [System.Xml.XmlNodeReader]::new($xaml)
|
||||
$window = [System.Windows.Markup.XamlReader]::Load($reader)
|
||||
|
||||
# ── Set window icon ───────────────────────────────────────────────────────────
|
||||
$iconPath = Join-Path (Split-Path -Parent $MyInvocation.MyCommand.Path) "uplink_manager.ico"
|
||||
if (-not $iconPath -or -not (Test-Path $iconPath)) { $iconPath = Join-Path $PSScriptRoot "uplink_manager.ico" }
|
||||
if (Test-Path $iconPath) {
|
||||
$window.Icon = [System.Windows.Media.Imaging.BitmapFrame]::Create([uri]$iconPath)
|
||||
}
|
||||
|
||||
$PageContainer = $window.FindName("PageContainer")
|
||||
$BtnNext = $window.FindName("BtnNext")
|
||||
$BtnBack = $window.FindName("BtnBack")
|
||||
$FooterStatus = $window.FindName("FooterStatus")
|
||||
|
||||
# ── UI Helpers ────────────────────────────────────────────────────────────────
|
||||
function New-SectionTitle {
|
||||
param([string]$text)
|
||||
$tb = [System.Windows.Controls.TextBlock]::new()
|
||||
$tb.Text = $text; $tb.FontSize = 16; $tb.FontWeight = "Bold"
|
||||
$tb.Foreground = [System.Windows.Media.BrushConverter]::new().ConvertFromString($YELLOW)
|
||||
$tb.Margin = [System.Windows.Thickness]::new(0, 0, 0, 8)
|
||||
return $tb
|
||||
}
|
||||
|
||||
function New-BodyText {
|
||||
param([string]$text, [object]$color = $TEXT_MUTED)
|
||||
$tb = [System.Windows.Controls.TextBlock]::new()
|
||||
$tb.Text = $text; $tb.FontSize = 12; $tb.TextWrapping = "Wrap"
|
||||
if ($color -is [System.Windows.Media.Brush]) {
|
||||
$tb.Foreground = $color
|
||||
}
|
||||
else {
|
||||
$tb.Foreground = [System.Windows.Media.BrushConverter]::new().ConvertFromString([string]$color)
|
||||
}
|
||||
$tb.Margin = [System.Windows.Thickness]::new(0, 0, 0, 6)
|
||||
return $tb
|
||||
}
|
||||
|
||||
function New-Separator {
|
||||
$sep = [System.Windows.Controls.Separator]::new()
|
||||
$sep.Background = [System.Windows.Media.BrushConverter]::new().ConvertFromString($PANEL)
|
||||
$sep.Margin = [System.Windows.Thickness]::new(0, 8, 0, 12)
|
||||
return $sep
|
||||
}
|
||||
|
||||
function New-CheckRow {
|
||||
param([string]$label, [bool]$passed, [string]$detail = "")
|
||||
$sp = [System.Windows.Controls.StackPanel]::new()
|
||||
$sp.Orientation = "Horizontal"; $sp.Margin = [System.Windows.Thickness]::new(0, 4, 0, 4)
|
||||
$dot = [System.Windows.Shapes.Ellipse]::new()
|
||||
$dot.Width = 10; $dot.Height = 10; $dot.Margin = [System.Windows.Thickness]::new(0, 0, 10, 0); $dot.VerticalAlignment = "Center"
|
||||
$dot.Fill = [System.Windows.Media.BrushConverter]::new().ConvertFromString($(if ($passed) { $GREEN_LT } else { $RED }))
|
||||
$sp.Children.Add($dot) | Out-Null
|
||||
$tb = [System.Windows.Controls.TextBlock]::new()
|
||||
$tb.Text = "$(if ($passed) { '✔' } else { '✘' }) $label"; $tb.FontSize = 12; $tb.VerticalAlignment = "Center"
|
||||
$tb.Foreground = [System.Windows.Media.BrushConverter]::new().ConvertFromString($TEXT)
|
||||
$sp.Children.Add($tb) | Out-Null
|
||||
if ($detail) {
|
||||
$dtb = [System.Windows.Controls.TextBlock]::new()
|
||||
$dtb.Text = " - $detail"; $dtb.FontSize = 11; $dtb.VerticalAlignment = "Center"
|
||||
$dtb.Foreground = [System.Windows.Media.BrushConverter]::new().ConvertFromString($TEXT_MUTED)
|
||||
$sp.Children.Add($dtb) | Out-Null
|
||||
}
|
||||
return $sp
|
||||
}
|
||||
|
||||
function New-StyledListBox {
|
||||
param([string[]]$items)
|
||||
$lb = [System.Windows.Controls.ListBox]::new()
|
||||
$lb.Background = [System.Windows.Media.BrushConverter]::new().ConvertFromString("#2e3038")
|
||||
$lb.Foreground = [System.Windows.Media.BrushConverter]::new().ConvertFromString("#ebdbb2")
|
||||
$lb.BorderBrush = [System.Windows.Media.BrushConverter]::new().ConvertFromString("#404450")
|
||||
$lb.BorderThickness = [System.Windows.Thickness]::new(1)
|
||||
$lb.FontFamily = [System.Windows.Media.FontFamily]::new("Consolas")
|
||||
$lb.FontSize = 12; $lb.Height = 80
|
||||
$lb.Margin = [System.Windows.Thickness]::new(0, 4, 0, 12)
|
||||
[System.Windows.Controls.ScrollViewer]::SetHorizontalScrollBarVisibility($lb, [System.Windows.Controls.ScrollBarVisibility]::Disabled)
|
||||
$itemStyle = [System.Windows.Style]::new([System.Windows.Controls.ListBoxItem])
|
||||
$bgS = [System.Windows.Setter]::new(); $bgS.Property = [System.Windows.Controls.Control]::BackgroundProperty; $bgS.Value = [System.Windows.Media.BrushConverter]::new().ConvertFromString("#2e3038"); $itemStyle.Setters.Add($bgS)
|
||||
$fgS = [System.Windows.Setter]::new(); $fgS.Property = [System.Windows.Controls.Control]::ForegroundProperty; $fgS.Value = [System.Windows.Media.BrushConverter]::new().ConvertFromString("#ebdbb2"); $itemStyle.Setters.Add($fgS)
|
||||
$pdS = [System.Windows.Setter]::new(); $pdS.Property = [System.Windows.Controls.Control]::PaddingProperty; $pdS.Value = [System.Windows.Thickness]::new(8, 4, 8, 4); $itemStyle.Setters.Add($pdS)
|
||||
$hvT = [System.Windows.Trigger]::new(); $hvT.Property = [System.Windows.Controls.ListBoxItem]::IsMouseOverProperty; $hvT.Value = $true
|
||||
$hvBg = [System.Windows.Setter]::new(); $hvBg.Property = [System.Windows.Controls.Control]::BackgroundProperty; $hvBg.Value = [System.Windows.Media.BrushConverter]::new().ConvertFromString("#fabd2f")
|
||||
$hvFg = [System.Windows.Setter]::new(); $hvFg.Property = [System.Windows.Controls.Control]::ForegroundProperty; $hvFg.Value = [System.Windows.Media.BrushConverter]::new().ConvertFromString("#1e1e1e")
|
||||
$hvT.Setters.Add($hvBg); $hvT.Setters.Add($hvFg); $itemStyle.Triggers.Add($hvT)
|
||||
$slT = [System.Windows.Trigger]::new(); $slT.Property = [System.Windows.Controls.ListBoxItem]::IsSelectedProperty; $slT.Value = $true
|
||||
$slBg = [System.Windows.Setter]::new(); $slBg.Property = [System.Windows.Controls.Control]::BackgroundProperty; $slBg.Value = [System.Windows.Media.BrushConverter]::new().ConvertFromString("#3d5c3f")
|
||||
$slFg = [System.Windows.Setter]::new(); $slFg.Property = [System.Windows.Controls.Control]::ForegroundProperty; $slFg.Value = [System.Windows.Media.BrushConverter]::new().ConvertFromString("#ebdbb2")
|
||||
$slT.Setters.Add($slBg); $slT.Setters.Add($slFg); $itemStyle.Triggers.Add($slT)
|
||||
$suT = [System.Windows.MultiTrigger]::new()
|
||||
$sc1 = [System.Windows.Condition]::new(); $sc1.Property = [System.Windows.Controls.ListBoxItem]::IsSelectedProperty; $sc1.Value = $true
|
||||
$sc2 = [System.Windows.Condition]::new(); $sc2.Property = [System.Windows.Controls.ListBoxItem]::IsKeyboardFocusWithinProperty; $sc2.Value = $false
|
||||
$suT.Conditions.Add($sc1); $suT.Conditions.Add($sc2)
|
||||
$suBg = [System.Windows.Setter]::new(); $suBg.Property = [System.Windows.Controls.Control]::BackgroundProperty; $suBg.Value = [System.Windows.Media.BrushConverter]::new().ConvertFromString("#3d5c3f")
|
||||
$suFg = [System.Windows.Setter]::new(); $suFg.Property = [System.Windows.Controls.Control]::ForegroundProperty; $suFg.Value = [System.Windows.Media.BrushConverter]::new().ConvertFromString("#ebdbb2")
|
||||
$suT.Setters.Add($suBg); $suT.Setters.Add($suFg); $itemStyle.Triggers.Add($suT)
|
||||
$lb.ItemContainerStyle = $itemStyle
|
||||
foreach ($item in $items) { $lb.Items.Add($item) | Out-Null }
|
||||
return $lb
|
||||
}
|
||||
|
||||
function Add-PassRow {
|
||||
param($panel, [string]$text)
|
||||
$row = [System.Windows.Controls.StackPanel]::new(); $row.Orientation = "Horizontal"; $row.Margin = [System.Windows.Thickness]::new(0, 4, 0, 4)
|
||||
$greenBrush = [System.Windows.Media.BrushConverter]::new().ConvertFromString($GREEN_LT)
|
||||
$icon = [System.Windows.Controls.TextBlock]::new(); $icon.Text = "✔"; $icon.FontSize = 14; $icon.FontWeight = "Bold"
|
||||
$icon.Foreground = $greenBrush; $icon.Margin = [System.Windows.Thickness]::new(0, 0, 10, 0); $icon.VerticalAlignment = "Center"; $row.Children.Add($icon) | Out-Null
|
||||
$txt = [System.Windows.Controls.TextBlock]::new(); $txt.Text = $text; $txt.FontSize = 12; $txt.VerticalAlignment = "Center"
|
||||
$txt.Foreground = $greenBrush; $row.Children.Add($txt) | Out-Null
|
||||
$panel.Children.Add($row) | Out-Null
|
||||
}
|
||||
|
||||
function Add-FailBlock {
|
||||
param($panel, [string]$title, [string[]]$hints)
|
||||
$block = [System.Windows.Controls.StackPanel]::new(); $block.Orientation = "Vertical"; $block.Margin = [System.Windows.Thickness]::new(0, 4, 0, 8)
|
||||
$hdr = [System.Windows.Controls.StackPanel]::new(); $hdr.Orientation = "Horizontal"
|
||||
$icon = [System.Windows.Controls.TextBlock]::new(); $icon.Text = "🛑"; $icon.FontSize = 14; $icon.Margin = [System.Windows.Thickness]::new(0, 0, 10, 0); $icon.VerticalAlignment = "Center"; $hdr.Children.Add($icon) | Out-Null
|
||||
$ttl = [System.Windows.Controls.TextBlock]::new(); $ttl.Text = $title; $ttl.FontSize = 12; $ttl.FontWeight = "Bold"; $ttl.VerticalAlignment = "Center"
|
||||
$ttl.Foreground = [System.Windows.Media.BrushConverter]::new().ConvertFromString($RED); $hdr.Children.Add($ttl) | Out-Null
|
||||
$block.Children.Add($hdr) | Out-Null
|
||||
foreach ($hint in $hints) {
|
||||
$h = [System.Windows.Controls.TextBlock]::new(); $h.Text = " $hint"; $h.FontSize = 11; $h.Margin = [System.Windows.Thickness]::new(24, 2, 0, 0)
|
||||
$h.Foreground = [System.Windows.Media.BrushConverter]::new().ConvertFromString($TEXT_MUTED); $block.Children.Add($h) | Out-Null
|
||||
}
|
||||
$panel.Children.Add($block) | Out-Null
|
||||
}
|
||||
|
||||
# ── Page 0: Welcome ───────────────────────────────────────────────────────────
|
||||
function Show-PageWelcome {
|
||||
$PageContainer.Children.Clear()
|
||||
$sp = [System.Windows.Controls.StackPanel]::new()
|
||||
$sp.Margin = [System.Windows.Thickness]::new(32, 24, 32, 0)
|
||||
$sp.Children.Add((New-SectionTitle "Welcome to Uplink Manager Setup")) | Out-Null
|
||||
$sp.Children.Add((New-Separator)) | Out-Null
|
||||
$sp.Children.Add((New-BodyText "This installer will configure your Windows 11 Pro VM to run Uplink Manager — a tool for engineers to set up network address translation from an internet-facing adapter to a downstream NAT Uplink adapter.")) | Out-Null
|
||||
$sp.Children.Add((New-BodyText "The following will be configured on this VM:")) | Out-Null
|
||||
foreach ($step in @(
|
||||
"Rename selected adapters to Internet VLAN and NAT Uplink",
|
||||
"Enable Hyper-V Services (required for WinNAT)",
|
||||
"Register Windows NAT WMI provider (netttcim.dll)",
|
||||
"Install Uplink Manager to $($script:InstallDir)",
|
||||
"Create desktop shortcut"
|
||||
)) {
|
||||
$row = [System.Windows.Controls.StackPanel]::new(); $row.Orientation = "Horizontal"; $row.Margin = [System.Windows.Thickness]::new(8, 3, 0, 3)
|
||||
$dot = [System.Windows.Shapes.Ellipse]::new(); $dot.Width = 6; $dot.Height = 6; $dot.Margin = [System.Windows.Thickness]::new(0, 0, 10, 0); $dot.VerticalAlignment = "Center"
|
||||
$dot.Fill = [System.Windows.Media.BrushConverter]::new().ConvertFromString($YELLOW); $row.Children.Add($dot) | Out-Null
|
||||
$tb = [System.Windows.Controls.TextBlock]::new(); $tb.Text = $step; $tb.FontSize = 12
|
||||
$tb.Foreground = [System.Windows.Media.BrushConverter]::new().ConvertFromString($TEXT); $row.Children.Add($tb) | Out-Null
|
||||
$sp.Children.Add($row) | Out-Null
|
||||
}
|
||||
$sp.Children.Add((New-Separator)) | Out-Null
|
||||
$sp.Children.Add((New-BodyText "Before continuing, ensure this VM has at least 2 vmxnet3 adapters and hardware virtualization (Expose VT-x to guest) is enabled in VM processor settings." $TEXT_MUTED)) | Out-Null
|
||||
$PageContainer.Children.Add($sp) | Out-Null
|
||||
$BtnBack.Visibility = "Collapsed"
|
||||
$BtnNext.Content = "Begin Setup →"; $BtnNext.IsEnabled = $true
|
||||
$BtnNext.Background = [System.Windows.Media.BrushConverter]::new().ConvertFromString($GREEN)
|
||||
$FooterStatus.Text = "Step 1 of 6"
|
||||
}
|
||||
|
||||
# ── Page 1: Pre-Installation Requirements ────────────────────────────────────
|
||||
function Show-PageRequirements {
|
||||
$PageContainer.Children.Clear()
|
||||
$sp = [System.Windows.Controls.StackPanel]::new()
|
||||
$sp.Margin = [System.Windows.Thickness]::new(32, 24, 32, 0)
|
||||
$sp.Children.Add((New-SectionTitle "Pre-Installation Requirements")) | Out-Null
|
||||
$sp.Children.Add((New-Separator)) | Out-Null
|
||||
$sp.Children.Add((New-BodyText "Checking VM configuration...")) | Out-Null
|
||||
$script:ReqResultsPanel = [System.Windows.Controls.StackPanel]::new()
|
||||
$sp.Children.Add($script:ReqResultsPanel) | Out-Null
|
||||
$sp.Children.Add((New-Separator)) | Out-Null
|
||||
$script:ReqWarning = New-BodyText "" $RED
|
||||
$sp.Children.Add($script:ReqWarning) | Out-Null
|
||||
$PageContainer.Children.Add($sp) | Out-Null
|
||||
$BtnBack.Visibility = "Visible"; $BtnNext.IsEnabled = $false
|
||||
$FooterStatus.Text = "Step 2 of 6"
|
||||
|
||||
$script:ReqJob = Start-Job -ScriptBlock {
|
||||
$virtOk = $false
|
||||
# Check if a hypervisor is present (most reliable)
|
||||
try {
|
||||
$cs = Get-CimInstance -ClassName Win32_ComputerSystem -ErrorAction Stop
|
||||
if ($cs.HypervisorPresent -eq $true) { $virtOk = $true }
|
||||
}
|
||||
catch {}
|
||||
# If not detected, check if Hyper‑V feature is installed
|
||||
if (-not $virtOk) {
|
||||
try {
|
||||
$hyperV = Get-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V-Platform -ErrorAction SilentlyContinue
|
||||
if ($hyperV.State -eq "Enabled") { $virtOk = $true }
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
# Optionally check Virtualization‑Based Security registry (indicates hypervisor)
|
||||
if (-not $virtOk) {
|
||||
try {
|
||||
$reg = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\DeviceGuard" -Name "EnableVirtualizationBasedSecurity" -ErrorAction SilentlyContinue
|
||||
if ($reg.EnableVirtualizationBasedSecurity -eq 1) { $virtOk = $true }
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
$adapters = @(Get-NetAdapter | Where-Object { $_.InterfaceDescription -like "*vmxnet3*" -and $_.Status -eq "Up" } | Select-Object -ExpandProperty Name)
|
||||
[PSCustomObject]@{ VirtOk = $virtOk; Adapters = $adapters; AdapterOk = $adapters.Count -ge 2 }
|
||||
}
|
||||
|
||||
$window.Dispatcher.Invoke({
|
||||
$script:timerTickReq = 0
|
||||
$script:pollTimerReq = [System.Windows.Threading.DispatcherTimer]::new()
|
||||
$script:pollTimerReq.Interval = [TimeSpan]::FromMilliseconds(400)
|
||||
$script:pollTimerReq.Tag = $script:ReqJob
|
||||
$script:pollTimerReq.Add_Tick({
|
||||
$script:timerTickReq++
|
||||
if ($script:timerTickReq -gt 38) {
|
||||
$script:pollTimerReq.Stop()
|
||||
$script:ReqWarning.Text = "⚠ Check timed out after ~15 seconds. Please restart the installer."
|
||||
Stop-BtnSpinner; $BtnNext.IsEnabled = $false; return
|
||||
}
|
||||
$job = $script:pollTimerReq.Tag
|
||||
if ($null -eq $job) {
|
||||
$script:pollTimerReq.Stop()
|
||||
$script:ReqWarning.Text = "⚠ Background check could not be tracked. Please restart the installer."
|
||||
Stop-BtnSpinner; $BtnNext.IsEnabled = $false; return
|
||||
}
|
||||
if ($job.State -in "Completed", "Failed", "Stopped") {
|
||||
$script:pollTimerReq.Stop()
|
||||
$result = $null
|
||||
try { $result = Receive-Job -Job $job -ErrorAction Stop }
|
||||
catch { $script:ReqWarning.Text = "⚠ Failed to retrieve job result: $($_.Exception.Message)" }
|
||||
finally { Remove-Job -Job $job -Force -ErrorAction SilentlyContinue; $script:ReqJob = $null; $script:pollTimerReq.Tag = $null }
|
||||
|
||||
if ($null -eq $result) {
|
||||
$script:ReqWarning.Text = "⚠ Background check returned no data. Please restart the installer."
|
||||
Stop-BtnSpinner; $BtnNext.IsEnabled = $false
|
||||
$BtnNext.Background = [System.Windows.Media.BrushConverter]::new().ConvertFromString($PANEL)
|
||||
}
|
||||
else {
|
||||
if ($result.VirtOk) {
|
||||
Add-PassRow $script:ReqResultsPanel "Hardware virtualization exposed to guest OS"
|
||||
}
|
||||
else {
|
||||
Add-FailBlock $script:ReqResultsPanel "Hardware virtualization not detected" @(
|
||||
"— Shutdown this VM",
|
||||
"— In VMware: VM Settings → Processors",
|
||||
"— Enable: Expose hardware assisted virtualization to the guest OS"
|
||||
)
|
||||
}
|
||||
if ($result.AdapterOk) {
|
||||
Add-PassRow $script:ReqResultsPanel "vmxnet3 adapters detected — $($result.Adapters.Count) found"
|
||||
}
|
||||
else {
|
||||
Add-FailBlock $script:ReqResultsPanel "Insufficient vmxnet3 adapters — $($result.Adapters.Count) found (minimum 2 required)" @(
|
||||
"— Shutdown this VM",
|
||||
"— In VMware: VM Settings → Network Adapters",
|
||||
"— Add at least 2 vmxnet3 network adapters"
|
||||
)
|
||||
}
|
||||
$listBlock = [System.Windows.Controls.StackPanel]::new(); $listBlock.Margin = [System.Windows.Thickness]::new(24, 4, 0, 0)
|
||||
foreach ($adapter in $result.Adapters) {
|
||||
$r = [System.Windows.Controls.TextBlock]::new(); $r.Text = "· $adapter"; $r.FontSize = 11; $r.Margin = [System.Windows.Thickness]::new(0, 2, 0, 0)
|
||||
$r.Foreground = [System.Windows.Media.BrushConverter]::new().ConvertFromString($TEXT_MUTED); $listBlock.Children.Add($r) | Out-Null
|
||||
}
|
||||
$script:ReqResultsPanel.Children.Add($listBlock) | Out-Null
|
||||
$allOk = $result.VirtOk -and $result.AdapterOk
|
||||
if (-not $allOk) { $script:ReqWarning.Text = "⚠ Resolve the issues above before continuing. Shutdown the VM if required." }
|
||||
Stop-BtnSpinner
|
||||
if (-not $allOk) {
|
||||
$BtnNext.IsEnabled = $false
|
||||
$BtnNext.Background = [System.Windows.Media.BrushConverter]::new().ConvertFromString($PANEL)
|
||||
}
|
||||
else {
|
||||
$BtnNext.IsEnabled = $true; $BtnNext.Content = "Next →"
|
||||
$BtnNext.Background = [System.Windows.Media.BrushConverter]::new().ConvertFromString($GREEN)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
$script:pollTimerReq.Start()
|
||||
})
|
||||
}
|
||||
|
||||
# ── Page 2: VM Prerequisites ──────────────────────────────────────────────────
|
||||
function Show-PagePrereqs {
|
||||
$PageContainer.Children.Clear()
|
||||
$sp = [System.Windows.Controls.StackPanel]::new()
|
||||
$sp.Margin = [System.Windows.Thickness]::new(32, 24, 32, 0)
|
||||
$sp.Children.Add((New-SectionTitle "VM Prerequisites Check")) | Out-Null
|
||||
$sp.Children.Add((New-Separator)) | Out-Null
|
||||
$sp.Children.Add((New-BodyText "Verifying this VM meets requirements for Uplink Manager...")) | Out-Null
|
||||
$script:PrereqResultsPanel = [System.Windows.Controls.StackPanel]::new()
|
||||
$sp.Children.Add($script:PrereqResultsPanel) | Out-Null
|
||||
$sp.Children.Add((New-Separator)) | Out-Null
|
||||
$script:PrereqWarning = New-BodyText "" $RED
|
||||
$sp.Children.Add($script:PrereqWarning) | Out-Null
|
||||
$PageContainer.Children.Add($sp) | Out-Null
|
||||
$BtnBack.Visibility = "Visible"; $BtnNext.IsEnabled = $false
|
||||
$FooterStatus.Text = "Step 3 of 6"
|
||||
|
||||
$script:PrereqJob = Start-Job -ScriptBlock {
|
||||
$adminOk = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
$osVer = [System.Environment]::OSVersion.Version
|
||||
$winOk = $osVer.Major -ge 10
|
||||
$adapters = @(Get-NetAdapter | Where-Object { $_.InterfaceDescription -like "*vmxnet3*" -and $_.Status -eq "Up" } | Select-Object -ExpandProperty Name)
|
||||
$adapterOk = $adapters.Count -ge 2
|
||||
# Reliable virtualization detection
|
||||
$virtOk = $false
|
||||
try {
|
||||
$cs = Get-CimInstance -ClassName Win32_ComputerSystem -ErrorAction Stop
|
||||
if ($cs.HypervisorPresent -eq $true) { $virtOk = $true }
|
||||
}
|
||||
catch {}
|
||||
if (-not $virtOk) {
|
||||
try {
|
||||
$hyperV = Get-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V-Platform -ErrorAction SilentlyContinue
|
||||
if ($hyperV.State -eq "Enabled") { $virtOk = $true }
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
if (-not $virtOk) {
|
||||
try {
|
||||
$reg = Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\DeviceGuard" -Name "EnableVirtualizationBasedSecurity" -ErrorAction SilentlyContinue
|
||||
if ($reg.EnableVirtualizationBasedSecurity -eq 1) { $virtOk = $true }
|
||||
}
|
||||
catch {}
|
||||
}
|
||||
[PSCustomObject]@{ AdminOk = $adminOk; WinOk = $winOk; OsBuild = $osVer.Build; AdapterOk = $adapterOk; AdCount = $adapters.Count; VirtOk = $virtOk }
|
||||
}
|
||||
|
||||
$window.Dispatcher.Invoke({
|
||||
$script:timerTickPrereq = 0
|
||||
$script:pollTimerPrereq = [System.Windows.Threading.DispatcherTimer]::new()
|
||||
$script:pollTimerPrereq.Interval = [TimeSpan]::FromMilliseconds(400)
|
||||
$script:pollTimerPrereq.Tag = $script:PrereqJob
|
||||
$script:pollTimerPrereq.Add_Tick({
|
||||
$script:timerTickPrereq++
|
||||
if ($script:timerTickPrereq -gt 38) {
|
||||
$script:pollTimerPrereq.Stop()
|
||||
$script:PrereqWarning.Text = "⚠ Prerequisite check timed out after ~15 seconds."
|
||||
Stop-BtnSpinner; $BtnNext.IsEnabled = $false; return
|
||||
}
|
||||
$job = $script:pollTimerPrereq.Tag
|
||||
if ($null -eq $job) {
|
||||
$script:pollTimerPrereq.Stop()
|
||||
$script:PrereqWarning.Text = "⚠ Prerequisite check could not be tracked. Please restart the installer."
|
||||
Stop-BtnSpinner; $BtnNext.IsEnabled = $false; return
|
||||
}
|
||||
if ($job.State -in "Completed", "Failed", "Stopped") {
|
||||
$script:pollTimerPrereq.Stop()
|
||||
$r = $null
|
||||
try { $r = Receive-Job -Job $job -ErrorAction Stop }
|
||||
catch { $script:PrereqWarning.Text = "⚠ Failed to retrieve prerequisite check result: $($_.Exception.Message)" }
|
||||
finally { Remove-Job -Job $job -Force -ErrorAction SilentlyContinue; $script:PrereqJob = $null; $script:pollTimerPrereq.Tag = $null }
|
||||
|
||||
if ($null -eq $r) {
|
||||
$script:PrereqWarning.Text = "⚠ Prerequisite check returned no data. Please restart the installer."
|
||||
Stop-BtnSpinner; $BtnNext.IsEnabled = $false
|
||||
$BtnNext.Background = [System.Windows.Media.BrushConverter]::new().ConvertFromString($PANEL)
|
||||
}
|
||||
else {
|
||||
$script:PrereqResultsPanel.Children.Add((New-CheckRow "Running as Administrator" $r.AdminOk)) | Out-Null
|
||||
$script:PrereqResultsPanel.Children.Add((New-CheckRow "Windows 10/11 detected" $r.WinOk "Build $($r.OsBuild)")) | Out-Null
|
||||
$script:PrereqResultsPanel.Children.Add((New-CheckRow "At least 2 vmxnet3 adapters present" $r.AdapterOk "$($r.AdCount) found")) | Out-Null
|
||||
$script:PrereqResultsPanel.Children.Add((New-CheckRow "Hardware virtualization exposed to VM" $r.VirtOk $(if (-not $r.VirtOk) { "Enable in VMware VM Settings → Processors" } else { "" }))) | Out-Null
|
||||
$allOk = $r.AdminOk -and $r.WinOk -and $r.AdapterOk
|
||||
if (-not $allOk) {
|
||||
$script:PrereqWarning.Text = "⚠ One or more checks failed. Please resolve the issues above before continuing."
|
||||
}
|
||||
else {
|
||||
$script:PrereqResultsPanel.Children.Add((New-BodyText "✔ All critical checks passed. You may continue." $GREEN_LT)) | Out-Null
|
||||
}
|
||||
Stop-BtnSpinner
|
||||
if (-not $allOk) {
|
||||
$BtnNext.IsEnabled = $false
|
||||
$BtnNext.Background = [System.Windows.Media.BrushConverter]::new().ConvertFromString($PANEL)
|
||||
}
|
||||
else {
|
||||
$BtnNext.IsEnabled = $true; $BtnNext.Content = "Next →"
|
||||
$BtnNext.Background = [System.Windows.Media.BrushConverter]::new().ConvertFromString($GREEN)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
$script:pollTimerPrereq.Start()
|
||||
})
|
||||
}
|
||||
|
||||
# ── Page 3: Adapter selection ─────────────────────────────────────────────────
|
||||
function Show-PageAdapters {
|
||||
$PageContainer.Children.Clear()
|
||||
$sp = [System.Windows.Controls.StackPanel]::new()
|
||||
$sp.Margin = [System.Windows.Thickness]::new(32, 24, 32, 0)
|
||||
$sp.Children.Add((New-SectionTitle "Configure Network Adapters")) | Out-Null
|
||||
$sp.Children.Add((New-Separator)) | Out-Null
|
||||
$sp.Children.Add((New-BodyText "Select which adapter serves each role. They will be renamed to match what Uplink Manager expects.")) | Out-Null
|
||||
$adapters = Get-Vmxnet3Adapters
|
||||
$tb1 = New-BodyText "Internet-facing adapter (WAN uplink — receives internet from your network)"
|
||||
$tb1.FontWeight = "Bold"; $tb1.Foreground = [System.Windows.Media.BrushConverter]::new().ConvertFromString($TEXT); $sp.Children.Add($tb1) | Out-Null
|
||||
$script:ComboInternet = New-StyledListBox $adapters
|
||||
if ($script:SelectedInternet) { $script:ComboInternet.SelectedItem = $script:SelectedInternet }
|
||||
$sp.Children.Add($script:ComboInternet) | Out-Null
|
||||
$tb2 = New-BodyText "NAT Uplink adapter (downstream — connects to devices that need internet)"
|
||||
$tb2.FontWeight = "Bold"; $tb2.Foreground = [System.Windows.Media.BrushConverter]::new().ConvertFromString($TEXT); $sp.Children.Add($tb2) | Out-Null
|
||||
$script:ComboUplink = New-StyledListBox $adapters
|
||||
if ($script:SelectedUplink) { $script:ComboUplink.SelectedItem = $script:SelectedUplink }
|
||||
$sp.Children.Add($script:ComboUplink) | Out-Null
|
||||
$sp.Children.Add((New-Separator)) | Out-Null
|
||||
$script:AdapterWarning = New-BodyText "" $RED; $sp.Children.Add($script:AdapterWarning) | Out-Null
|
||||
$sp.Children.Add((New-BodyText "After selection, these adapters will be renamed: Internet VLAN and NAT Uplink" $TEXT_MUTED)) | Out-Null
|
||||
$PageContainer.Children.Add($sp) | Out-Null
|
||||
$BtnBack.Visibility = "Visible"
|
||||
$BtnNext.Content = "Next →"; $BtnNext.IsEnabled = $true
|
||||
$BtnNext.Background = [System.Windows.Media.BrushConverter]::new().ConvertFromString($GREEN)
|
||||
$FooterStatus.Text = "Step 4 of 6"
|
||||
Stop-BtnSpinner
|
||||
}
|
||||
|
||||
# ── Page 4: Confirm ───────────────────────────────────────────────────────────
|
||||
function Show-PageConfirm {
|
||||
$PageContainer.Children.Clear()
|
||||
$sp = [System.Windows.Controls.StackPanel]::new()
|
||||
$sp.Margin = [System.Windows.Thickness]::new(32, 24, 32, 0)
|
||||
$sp.Children.Add((New-SectionTitle "Confirm Installation")) | Out-Null
|
||||
$sp.Children.Add((New-Separator)) | Out-Null
|
||||
$sp.Children.Add((New-BodyText "The following changes will be made to this VM:")) | Out-Null
|
||||
foreach ($action in @(
|
||||
"Rename '$($script:SelectedInternet)' → Internet VLAN",
|
||||
"Rename '$($script:SelectedUplink)' → NAT Uplink",
|
||||
"Enable Hyper-V Services (may require reboot)",
|
||||
"Register netttcim.dll WMI provider",
|
||||
"Compile netttcim.mof WMI class definitions",
|
||||
"Create desktop shortcut (no arrow overlay)"
|
||||
)) {
|
||||
$row = [System.Windows.Controls.StackPanel]::new(); $row.Orientation = "Horizontal"; $row.Margin = [System.Windows.Thickness]::new(8, 4, 0, 4)
|
||||
$dot = [System.Windows.Shapes.Ellipse]::new(); $dot.Width = 6; $dot.Height = 6; $dot.Margin = [System.Windows.Thickness]::new(0, 0, 10, 0); $dot.VerticalAlignment = "Center"
|
||||
$dot.Fill = [System.Windows.Media.BrushConverter]::new().ConvertFromString($YELLOW); $row.Children.Add($dot) | Out-Null
|
||||
$tb = [System.Windows.Controls.TextBlock]::new(); $tb.Text = $action; $tb.FontSize = 12
|
||||
$tb.Foreground = [System.Windows.Media.BrushConverter]::new().ConvertFromString($TEXT); $row.Children.Add($tb) | Out-Null
|
||||
$sp.Children.Add($row) | Out-Null
|
||||
}
|
||||
$sp.Children.Add((New-Separator)) | Out-Null
|
||||
$PageContainer.Children.Add($sp) | Out-Null
|
||||
$BtnBack.Visibility = "Visible"
|
||||
$BtnNext.Content = "⚡ Install"; $BtnNext.IsEnabled = $true
|
||||
$BtnNext.Background = [System.Windows.Media.BrushConverter]::new().ConvertFromString($GREEN)
|
||||
$FooterStatus.Text = "Step 5 of 6"
|
||||
Stop-BtnSpinner
|
||||
}
|
||||
|
||||
# ── Page 5: Install ───────────────────────────────────────────────────────────
|
||||
function Show-PageInstall {
|
||||
$PageContainer.Children.Clear()
|
||||
$BtnBack.Visibility = "Collapsed"
|
||||
$sp = [System.Windows.Controls.StackPanel]::new()
|
||||
$sp.Margin = [System.Windows.Thickness]::new(32, 24, 32, 0)
|
||||
|
||||
# Section title that we will update later
|
||||
$script:installTitle = New-SectionTitle "Installing..."
|
||||
$sp.Children.Add($script:installTitle) | Out-Null
|
||||
$sp.Children.Add((New-Separator)) | Out-Null
|
||||
|
||||
$script:LogBox = [System.Windows.Controls.TextBlock]::new()
|
||||
$script:LogBox.FontSize = 11
|
||||
$script:LogBox.FontFamily = [System.Windows.Media.FontFamily]::new("Consolas")
|
||||
$script:LogBox.Foreground = [System.Windows.Media.BrushConverter]::new().ConvertFromString($TEXT_MUTED)
|
||||
$script:LogBox.TextWrapping = "Wrap"; $script:LogBox.Text = ""
|
||||
|
||||
$scroll = [System.Windows.Controls.ScrollViewer]::new()
|
||||
$scroll.Height = 290
|
||||
$scroll.VerticalScrollBarVisibility = [System.Windows.Controls.ScrollBarVisibility]::Hidden # hides vertical scroll bar
|
||||
$scroll.HorizontalScrollBarVisibility = [System.Windows.Controls.ScrollBarVisibility]::Disabled # prevents horizontal scroll bar
|
||||
$scroll.Content = $script:LogBox
|
||||
$scroll.Background = [System.Windows.Media.BrushConverter]::new().ConvertFromString($SURFACE)
|
||||
$scroll.Padding = [System.Windows.Thickness]::new(8)
|
||||
|
||||
$sp.Children.Add($scroll) | Out-Null
|
||||
$PageContainer.Children.Add($sp) | Out-Null
|
||||
$FooterStatus.Text = "Step 6 of 6 — Installing..."
|
||||
|
||||
# Create a temporary log file
|
||||
$script:LogFilePath = Join-Path $env:TEMP "uplink_install_log_$pid.txt"
|
||||
if (Test-Path $script:LogFilePath) { Remove-Item $script:LogFilePath -Force }
|
||||
|
||||
# Start background job that writes to the log file
|
||||
$script:InstallJob = Start-Job -Name "UplinkInstall" -ScriptBlock {
|
||||
param($SelectedInternet, $SelectedUplink, $InstallDir, $LogFilePath)
|
||||
|
||||
function Write-LogLine { param($Line) $Line | Out-File -FilePath $LogFilePath -Append -Encoding UTF8 }
|
||||
|
||||
$ok = $true
|
||||
$needsReboot = $false
|
||||
|
||||
Write-LogLine "── Configuring Network Adapters ────────────────────"
|
||||
try {
|
||||
Rename-NetAdapter -Name $SelectedInternet -NewName "Internet VLAN" -ErrorAction Stop
|
||||
Write-LogLine " ✔ Renamed '$SelectedInternet' → 'Internet VLAN'"
|
||||
} catch {
|
||||
Write-LogLine " ✘ Failed to rename Internet adapter: $_"
|
||||
$ok = $false
|
||||
}
|
||||
try {
|
||||
Rename-NetAdapter -Name $SelectedUplink -NewName "NAT Uplink" -ErrorAction Stop
|
||||
Write-LogLine " ✔ Renamed '$SelectedUplink' → 'NAT Uplink'"
|
||||
} catch {
|
||||
Write-LogLine " ✘ Failed to rename NAT Uplink adapter: $_"
|
||||
$ok = $false
|
||||
}
|
||||
|
||||
Write-LogLine "── Enabling Hyper-V Services ────────────────────────"
|
||||
try {
|
||||
$proc = Start-Process -FilePath "dism.exe" -ArgumentList "/online /enable-feature /featurename:Microsoft-Hyper-V-Services /all /quiet /norestart" -Wait -PassThru -NoNewWindow
|
||||
if ($proc.ExitCode -eq 0 -or $proc.ExitCode -eq 3010) {
|
||||
$needsReboot = $true
|
||||
Write-LogLine " ✔ Hyper-V Services enabled (reboot required)"
|
||||
} else {
|
||||
Write-LogLine " ✘ Failed to enable Hyper-V Services, DISM exit code: $($proc.ExitCode)"
|
||||
$ok = $false
|
||||
}
|
||||
} catch {
|
||||
Write-LogLine " ✘ Failed to enable Hyper-V Services: $_"
|
||||
$ok = $false
|
||||
}
|
||||
|
||||
Write-LogLine "── Registering WMI NAT Provider ─────────────────────"
|
||||
$dllPath = "C:\Windows\System32\wbem\netttcim.dll"
|
||||
$mofPath = "C:\Windows\System32\wbem\netttcim.mof"
|
||||
if (Test-Path $dllPath) {
|
||||
try {
|
||||
$reg = Start-Process -FilePath "regsvr32.exe" -ArgumentList "/s `"$dllPath`"" -Wait -PassThru
|
||||
if ($reg.ExitCode -eq 0) { Write-LogLine " ✔ Registered netttcim.dll" } else { Write-LogLine " ⚠ regsvr32 returned $($reg.ExitCode)" }
|
||||
} catch { Write-LogLine " ✘ Failed to register DLL: $_" }
|
||||
} else { Write-LogLine " ✘ netttcim.dll not found"; $ok = $false }
|
||||
|
||||
if (Test-Path $mofPath) {
|
||||
try {
|
||||
$mof = Start-Process -FilePath "mofcomp.exe" -ArgumentList "`"$mofPath`"" -Wait -PassThru
|
||||
if ($mof.ExitCode -eq 0) { Write-LogLine " ✔ Compiled netttcim.mof" } else { Write-LogLine " ⚠ mofcomp returned $($mof.ExitCode)" }
|
||||
} catch { Write-LogLine " ✘ Failed to compile MOF: $_" }
|
||||
} else { Write-LogLine " ✘ netttcim.mof not found"; $ok = $false }
|
||||
|
||||
try {
|
||||
Restart-Service winmgmt -Force -ErrorAction SilentlyContinue; Start-Sleep -Seconds 2
|
||||
try { Get-CimClass -Namespace root/StandardCimv2 -ClassName MSFT_NetNat -ErrorAction Stop | Out-Null; $natOk = $true } catch { $natOk = $false }
|
||||
if ($natOk) { Write-LogLine " ✔ MSFT_NetNat WMI class verified" }
|
||||
else { Write-LogLine " ✔ MSFT_NetNat will be available after reboot (expected)"; $needsReboot = $true }
|
||||
} catch { Write-LogLine " ⚠ Could not restart WMI service" }
|
||||
|
||||
Write-LogLine "── Verifying Uplink Manager ────────────────────────────"
|
||||
$exeDest = Join-Path $InstallDir "Uplink Manager.exe"
|
||||
if (Test-Path $exeDest) {
|
||||
Write-LogLine " ✔ Uplink Manager.exe verified in $InstallDir"
|
||||
} else {
|
||||
Write-LogLine " ✘ Uplink Manager.exe missing from $InstallDir"
|
||||
$ok = $false
|
||||
}
|
||||
|
||||
Write-LogLine "── Creating Logs Folder ─────────────────────────────"
|
||||
$logsDir = Join-Path $InstallDir "logs"
|
||||
try {
|
||||
if (-not (Test-Path $logsDir)) {
|
||||
New-Item -ItemType Directory -Path $logsDir -Force | Out-Null
|
||||
Write-LogLine " ✔ Created logs folder: $logsDir"
|
||||
} else {
|
||||
Write-LogLine " ✔ Logs folder already exists: $logsDir"
|
||||
}
|
||||
} catch {
|
||||
Write-LogLine " ⚠ Could not create logs folder: $_"
|
||||
}
|
||||
|
||||
Write-LogLine "── Creating Desktop Shortcut ────────────────────────"
|
||||
try {
|
||||
$regPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Icons"
|
||||
if (-not (Test-Path $regPath)) { New-Item -Path $regPath -Force | Out-Null }
|
||||
Set-ItemProperty -Path $regPath -Name "29" -Value "%SystemRoot%\System32\imageres.dll,197" -Type String -Force
|
||||
Write-LogLine " ✔ Shortcut arrow overlay removed"
|
||||
$shortcutPath = [System.IO.Path]::Combine([Environment]::GetFolderPath("Desktop"), "Uplink Manager.lnk")
|
||||
$shell = New-Object -ComObject WScript.Shell
|
||||
$shortcut = $shell.CreateShortcut($shortcutPath)
|
||||
$shortcut.TargetPath = $exeDest
|
||||
$shortcut.WorkingDirectory = $InstallDir
|
||||
$shortcut.Description = "Uplink Manager"
|
||||
$shortcut.Save()
|
||||
Write-LogLine " ✔ Desktop shortcut created"
|
||||
Stop-Process -Name explorer -Force -ErrorAction SilentlyContinue; Start-Sleep -Milliseconds 500
|
||||
} catch { Write-LogLine " ⚠ Shortcut creation issue: $_" }
|
||||
|
||||
Write-LogLine ""
|
||||
if ($ok) {
|
||||
Write-LogLine "✔ Installation complete!"
|
||||
if ($needsReboot) { Write-LogLine "⚠ A reboot is required to finalize Hyper-V Services and WMI changes." }
|
||||
} else {
|
||||
Write-LogLine "⚠ Installation completed with errors. Review log above."
|
||||
}
|
||||
|
||||
# Mark completion and reboot status
|
||||
Write-LogLine "___INSTALL_COMPLETE___"
|
||||
if ($needsReboot) { Write-LogLine "___REBOOT_REQUIRED___" } else { Write-LogLine "___NO_REBOOT___" }
|
||||
} -ArgumentList $script:SelectedInternet, $script:SelectedUplink, $script:InstallDir, $script:LogFilePath
|
||||
|
||||
# Timer to tail the log file
|
||||
$script:lastFileSize = 0
|
||||
$script:installPollTimer = [System.Windows.Threading.DispatcherTimer]::new()
|
||||
$script:installPollTimer.Interval = [TimeSpan]::FromMilliseconds(300)
|
||||
$script:installPollTimer.Add_Tick({
|
||||
if (-not (Test-Path $script:LogFilePath)) { return }
|
||||
$fs = [System.IO.File]::Open($script:LogFilePath, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::ReadWrite)
|
||||
$fs.Seek($script:lastFileSize, [System.IO.SeekOrigin]::Begin) | Out-Null
|
||||
$reader = [System.IO.StreamReader]::new($fs)
|
||||
$newLines = $reader.ReadToEnd()
|
||||
$script:lastFileSize = $fs.Position
|
||||
$reader.Close()
|
||||
$fs.Close()
|
||||
|
||||
if ($newLines) {
|
||||
$script:LogBox.Text += $newLines
|
||||
$script:LogBox.UpdateLayout()
|
||||
}
|
||||
|
||||
# Check for completion marker
|
||||
if ($newLines -like "*___INSTALL_COMPLETE___*") {
|
||||
$script:installPollTimer.Stop()
|
||||
$job = Get-Job -Name "UplinkInstall" -ErrorAction SilentlyContinue
|
||||
if ($job) { Receive-Job -Job $job; Remove-Job -Job $job -Force }
|
||||
# Clean up log file
|
||||
if (Test-Path $script:LogFilePath) { Remove-Item $script:LogFilePath -Force }
|
||||
|
||||
# Determine if reboot is needed from the log
|
||||
$needsReboot = $newLines -like "*___REBOOT_REQUIRED___*"
|
||||
$script:NeedsReboot = $needsReboot
|
||||
|
||||
# Update UI
|
||||
Stop-BtnSpinner
|
||||
if ($needsReboot) {
|
||||
$script:installTitle.Text = "Installed – Please Reboot"
|
||||
$BtnNext.Content = "Reboot Now"
|
||||
$FooterStatus.Text = "Done – Reboot required"
|
||||
} else {
|
||||
$script:installTitle.Text = "Installation Complete"
|
||||
$BtnNext.Content = "Finish"
|
||||
$FooterStatus.Text = "Done"
|
||||
}
|
||||
$BtnNext.IsEnabled = $true
|
||||
$BtnNext.Background = [System.Windows.Media.BrushConverter]::new().ConvertFromString($GREEN)
|
||||
$script:CurrentPage = 5
|
||||
}
|
||||
})
|
||||
$script:installPollTimer.Start()
|
||||
}
|
||||
|
||||
# ── Navigation ────────────────────────────────────────────────────────────────
|
||||
$BtnNext.Add_Click({
|
||||
Start-BtnSpinner
|
||||
switch ($script:CurrentPage) {
|
||||
0 { $script:CurrentPage = 1; Show-PageRequirements }
|
||||
1 { $script:CurrentPage = 2; Show-PagePrereqs }
|
||||
2 { $script:CurrentPage = 3; Show-PageAdapters }
|
||||
3 {
|
||||
$internet = $script:ComboInternet.SelectedItem
|
||||
$uplink = $script:ComboUplink.SelectedItem
|
||||
if (-not $internet -or -not $uplink) {
|
||||
$script:AdapterWarning.Text = "⚠ Please select both adapters before continuing."
|
||||
Stop-BtnSpinner; return
|
||||
}
|
||||
if ($internet -eq $uplink) {
|
||||
$script:AdapterWarning.Text = "⚠ Internet and NAT Uplink adapters must be different."
|
||||
Stop-BtnSpinner; return
|
||||
}
|
||||
$script:SelectedInternet = $internet; $script:SelectedUplink = $uplink
|
||||
$script:CurrentPage = 4; Show-PageConfirm
|
||||
}
|
||||
4 { $script:CurrentPage = 5; Show-PageInstall }
|
||||
5 { if ($script:NeedsReboot) { Restart-Computer -Force } else { $window.Close() } }
|
||||
}
|
||||
})
|
||||
|
||||
$BtnBack.Add_Click({
|
||||
switch ($script:CurrentPage) {
|
||||
1 { $script:CurrentPage = 0; Show-PageWelcome }
|
||||
2 { $script:CurrentPage = 1; Show-PageRequirements }
|
||||
3 { $script:CurrentPage = 2; Show-PagePrereqs }
|
||||
4 { $script:CurrentPage = 3; Show-PageAdapters }
|
||||
}
|
||||
})
|
||||
|
||||
# ── Launch ────────────────────────────────────────────────────────────────────
|
||||
Show-PageWelcome
|
||||
$window.ShowDialog() | Out-Null
|
||||
Reference in New Issue
Block a user