postman 发送 POST 请求服务器接收到却是 GET 请求

正常部署项目时,在本地测试请求一切都正常,但是将项目上传部署到服务器后,再发送请求却出现问题。

原本发送的是 POST 请求,可是服务器却返回 Cannot GET ×××,这个问题困扰了我好一会,经过搜索发现是自己大意导致的。

问题原因

因为服务器做了 HTTP 强制跳转 HTTPS。postman 发出的 POST 遇到 301 之后就会变成 GET。

解决方法

在请求地址前加 https:// 即可解决。

Nuxt 3 引入百度统计

使用 Nuxt 开发的时候会有相应的统计需求,这个时候可能会选用百度统计。但百度统计给的代码过于繁琐,经过在网络上搜索了很多教程以后,发现其实只有一行代码很重要。

操作步骤

nuxt.config.ts 中插入以下代码:

app: {
  head: {
    script: [{ src: `https://hm.baidu.com/hm.js?xxxxxx` }],
  },
},

https://hm.baidu.com/hm.js? 后面的内容替换成百度统计内给出的代码即可添加成功。

出现的问题

referrer 被禁用

在刚开始测试代码安装的时候,百度统计内的代码检查提示:“referrer 被禁用”,通过搜索找到了对应的解决方法。

解决方法

因为我是用的是 nginx 作为反向代理器,所以添加以下加租代码:

server {
     # HTTPS的默认访问端口443。
     # 如果未在此处配置HTTPS的默认访问端口,可能会造成Nginx无法启动。
     listen 443 ssl;

     # ......其他设置

     # 设置 Referrer Policy
     add_header Referrer-Policy origin;

}

这样再次执行代码安装检查,就会显示代码安装正确了。

引用

网站百度统计referrer被禁用解决方案

nuxt 引入百度统计

使用 Git 无法正常向 GitHub Push Commits

作为开发人员,我们经常使用 Git 向 GitHub 提交和拉取代码,但有时提交代码一直提示 Failed to connect to github.com port 443 after ××××× ms: Couldn't connect to server 导致一直提示提交错误。

解决方法

获取 Windows 当前代理端口号

Windows:设置-网络和 Internet -代理- 手动设置代理(不同系统版本之间大同小异)

点击“编辑”按钮后,查看当前显示的“端口”号并记住它。

为 Git 配置代理

git config --global http.proxy http://127.0.0.1:端口号
git config --global https.proxy http://127.0.0.1:端口号

上面两条代码都需要执行,且需要用到设备代理页面中显示的端口。如果不需要修改全局 Git 配置则 --global 可不写,这样只修改当前项目的 Git 配置。

为 Git 配置取消代理

git config --global --unset http.proxy
git config --global --unset https.proxy

如果上述配置代理不生效未能解决问题,可使用这两条语句取消代理。

Docker 相关容器配置

更新时间:2023年12月25日
– 更新 Vaultwarden

更新时间:2023年7月11日
– 新增 qbittorrent

自从服务器重置以后,重新安装了 Docker,下面记录一下正在使用的容器和相关配置内容。

创建容器间网络

docker network create -d bridge individual

Nginx

docker run -d \
--name nginx \
-p 80:80 \
-p 443:443 \
-v $PWD/nginx/html:/usr/share/nginx/html \
-v $PWD/nginx/nginx.conf:/etc/nginx/nginx.conf \
-v $PWD/nginx/log:/var/log/nginx \
-v $PWD/nginx/cert:/etc/nginx/cert \
-v $PWD/nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf \
--restart=always \
nginx

MySQL

docker run -d \
--name mysql \
-p 3306:3306 \
-v $PWD/mysql/log:/var/log/mysql \
-v $PWD/mysql/data:/var/lib/mysql \
-v $PWD/mysql/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
--restart=always \
--network individual mysql --lower_case_table_names=1

MySQL 密码修改

ALTER USER 'root'@'%' IDENTIFIED WITH [mysql_native_password, caching_sha2_password] BY '123456';

MySQL 配置

进入 $PWD/mysql/conf/conf.d/ 创建 mysqld.cnf 文件,粘贴以下内容:

[mysqld]
performance_schema_max_table_instances=400
table_definition_cache=400 #缓存
performance_schema=off #用于监控MySQL server在一个较低级别的运行过程中的资源消耗、资源东西
table_open_cache=64 #打开表的缓存
innodb_buffer_pool_chunk_size=64M #InnoDB缓冲池大小调整操作的块大小
innodb_buffer_pool_size=64M #InnoDB 存储引擎的表数据和索引数据的最大内存缓冲区大小

phpMyAdmin

docker run -d \
--name phpmyadmin \
--network individual \
-e PMA_HOST="mysql" \
-p 80:80 \
--restart=always \
phpmyadmin

Redis

创建目录:
mkdir -p $PWD/redis/conf
创建文件:
touch $PWD/redis/conf/redis.conf

docker run -d \
--name redis \
-p 6379:6379 \
--network individual \
-v $PWD/redis/data:/data \
-v $PWD/redis/conf:/etc/redis \
--restart=always \
redis \
redis-server /etc/redis/redis.conf \
--appendonly yes

Warchtowe

docker run -d \
--name watchtower \
--restart=always \
-v /var/run/docker.sock:/var/run/docker.sock  \
containrrr/watchtower \
--cleanup \
-i 3600

WordPress

docker run -d \
--name wordpress \
--network individual \
--restart=always \
-v $PWD/wordpress:/var/www/html \
-p 8080:80 \
wordpress

Vaultwarden

docker run -d \
--name vaultwarden \
--restart=always \
--network individual \
-v $PWD/vaultwarden:/data \
-p 90090:80 \
-e RUST_BACKTRACE=1 \
-e DATABASE_URL='mysql://username:password@mysql/vaultwarden' \
-e ADMIN_TOKEN=admin_token \
-e ENABLE_DB_WAL='false' \
vaultwarden/server:latest

QianDao

docker run -d \
--name qiandao \
--restart=always \
-p 80:80 \
-v $(pwd)/qiandao/config:/usr/src/app/config \
a76yyyy/qiandao

QingLong

docker run -dit \
--name qinglong \
--restart=always \
-p 5775:5700 \
-v $PWD/ql:/ql/data \
whyour/qinglong:latest

qbittorrent

docker run -d \
  --name=qbittorrent \
  -e PUID=1000 \
  -e PGID=1000 \
  -e TZ=Asia/Shanghai \
  -e WEBUI_PORT=8090 \
  -p 9821:6881 \
  -p 9821:6881/udp \
  -p 8090:8090 \
  -v /data/qbittorrent/config:/config \
  -v /data/qbittorrent/downloads:/downloads \
  --restart=always \
  lscr.io/linuxserver/qbittorrent:latest

WordPress 显示链接功能

WordPress 自 3.5 版本以后,默认隐藏了“链接”的功能,如果我们需要添加友情连接,可以借助插件或者修改代码的方式进行操作。但是本人不喜欢安装太多插件,所以使用修改代码的方式显示“链接”功能,进而添加友情链接。

“链接”功能显示方式

将下列代码添加进当前主题的 functions.php 即可:

add_filter('pre_option_link_manager_enabled','__return_true');

将上述代码粘贴至 functions.php 后,点击“更新文件”即可在左侧选择栏中看到“链接”功能。

你还想知道……

如何替换 Gravatar 头像?点击查看解决方案

连接共享打印机提示 Operation could not be completed (error 0x00000709)

连接共享打印机时出现的问题

最近需要使用其他电脑连接的打印机打印内容。通过网络成功查找到对应的机器及相关打印机,但双击连接一直提示“Operation could not be completed (error0x00000709)
Double check the printer name and make sure that the printer is connected to the network.
”,通过不断搜索,最终在微软社区找到了解决办法。

如图提示 Operation could not be completed (error0x00000709)

当 Windows 11 尝试连接共享打印机时会出现错误消息 0x00000709,出现此错误是因为默认连接方法在 22H2 发生了更改。更改组策略编辑器中的设置可以解决该问题。

全新打印机策略是导致报错的罪魁祸首:RPC 连接设置。需要将其切换到命名管道,它才能再次工作。

解决办法

非 Windows 11 家庭版

请注意,在继续之前,您应该以管理员身份登录

在 Windows 搜索中键入“组策略”(Group Policy),然后按下 Enter 键。

导航到以下位置:
1. 管理模板 > 打印机
2. 双击打开右侧的配置“RPC 连接设置”。
3. 确保它是“已启用”。
4. 在下面的选项下,从下拉菜单中选择“通过命名管道进行 RPC” 。
5. 关闭该策略,然后打开“打印机浏览”。
6. 确保该选项已启用。

以上是翻译过的内容,原文如下:

This method helped most users to resolve the error. Note that you should be logged in as an administrator before proceeding.

  • Type Group Policy in Windows search and press Enter.
  • Navigate to the following location:
    Administrative Templates > Printers
  • Double-click to open Configure RPC connection settings on the right.
  • Make sure it is enabled.
  • Under Options below, pick RPC over named pipes from the drop-down menu.
  • Close down the policy and then open Printer Browsing.
  • Ensure the option is enabled.
Configure RPC connection settings

Windows 11 家庭版

对于 Windows 11 家庭版,请尝试注册表编辑(相当于组策略设置):

[HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Windows NT\Printers\RPC]

RpcUseNamedPipeProtocol 有 2 个值可以配置:

0:RpcOverTcp(默认)
1:RpcOverNamedPipes
将 0 更改为 1

通过上述操作,我的电脑已经自动安装好打印机驱动并可以正常使用共享打印机了。

以上是我遇到的相关问题解决方案,可能与你所遇到的问题相似或不同,解决方案可能有用或者无法解决,无法解决建议尝试搜索其他相关解决办法。

引用

Windows 11 Error message 0x00000709 while connecting to shared printer

How to fix printing error 0x00000709 (Operation could not be completed) in Windows?

基于 winston 实现 Nest.js 应用日志服务

Nest.js logo
Nest.js Logo

实现 Nest.js 应用日志服务有很多选择,较为出名的有:Log4jswinstonPino

这次就以 winston 为例,记录一下如何实现 Nest.js 应用日志服务。本文参考了搜索引擎中许多教程与案例,如果觉得有任何问题可以留言与我交流。

引入 winston

相关依赖:winston、nest-winston、winston-daily-rotate-file

pnpm install winston nest-winston winston-daily-rotate-file

winston-daily-rotate-file 用于实现日志文件的定期归档。由于应用日志量一般都非常大,因此需要定期自动对日志文件进行轮换、归档与删除。

配置 winston

app.module.ts

import {
  // ...
  Module,
} from '@nestjs/common';
import { WinstonModule } from 'nest-winston';
import * as winston from 'winston';
import 'winston-daily-rotate-file';
// ...

@Module({
  controllers: [],
  imports: [
    // ...
    WinstonModule.forRoot({
      transports: [
        new winston.transports.DailyRotateFile({
          dirname: `logs`, // 日志保存的目录
          filename: '%DATE%.log', // 日志名称,占位符 %DATE% 取值为 datePattern 值。
          datePattern: 'YYYY-MM-DD', // 日志轮换的频率,此处表示每天。
          zippedArchive: true, // 是否通过压缩的方式归档被轮换的日志文件。
          maxSize: '20m', // 设置日志文件的最大大小,m 表示 mb 。
          maxFiles: '14d', // 保留日志文件的最大天数,此处表示自动删除超过 14 天的日志文件。
          // 记录时添加时间戳信息
          format: winston.format.combine(
            winston.format.timestamp({
            	format: 'YYYY-MM-DD HH:mm:ss',
            }),
            winston.format.json(),
          ),
        }),
      ],
    }),
  ],
  // ...
})
export class AppModule { // ... }

在全局中间件、过滤器以及拦截器中记录日志

获取请求头信息的工具方法

getReqMainInfo.ts

import { Request } from 'express';

export const getReqMainInfo: (req: Request) => {
  [prop: string]: any;
} = req => {
  const { query, headers, url, method, body, connection } = req;

  // 获取 IP
  const xRealIp = headers['X-Real-IP'];
  const xForwardedFor = headers['X-Forwarded-For'];
  const { ip: cIp } = req;
  const { remoteAddress } = connection || {};
  const ip = xRealIp || xForwardedFor || cIp || remoteAddress;

  return {
    url,
    host: headers.host,
    ip,
    method,
    query,
    body,
  };
};

在全局中间件中记录日志

logger.middleware.ts

import { Inject, Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import { Logger } from 'winston';
import { getReqMainInfo } from '../../utils/getReqMainInfo';

@Injectable()
export default class LoggerMiddleware implements NestMiddleware {
  // 注入日志服务相关依赖
  constructor(
    @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger,
  ) {}

  use(req: Request, res: Response, next: NextFunction) {
    // 获取请求信息
    const {
      query,
      headers: { host },
      url,
      method,
      body,
    } = req;

    // 记录日志
    this.logger.info('route', {
      req: getReqMainInfo(req),
    });

    next();
  }
}

在全局异常过滤器中记录日志

uinify-exception.filter.ts

import {
  ArgumentsHost,
  Catch,
  ExceptionFilter,
  HttpException,
  HttpStatus,
  Inject,
} from '@nestjs/common';
import { Response, Request } from 'express';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import { Logger } from 'winston';
import { getReqMainInfo } from '../../utils/getReqMainInfo';

@Catch()
export default class UnifyExceptionFilter implements ExceptionFilter {
  // 注入日志服务相关依赖
  constructor(
    @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger,
  ) {}

  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp(); // 获取当前执行上下文
    const res = ctx.getResponse<Response>(); // 获取响应对象
    const req = ctx.getRequest<Request>(); // 获取请求对象
    const status =
      exception instanceof HttpException
        ? exception.getStatus()
        : HttpStatus.INTERNAL_SERVER_ERROR;

    const response = exception.getResponse();
    let msg =
      exception.message || (status >= 500 ? 'Service Error' : 'Client Error');
    if (Object.prototype.toString.call(response) === '[object Object]') {
      if (typeof response === 'string') {
        msg = response;
      }
    }
    const { query, headers, url, method, body } = req;

    // 记录日志(错误消息,错误码,请求信息等)
    this.logger.error(msg, {
      status,
      req: getReqMainInfo(req),
      // stack: exception.stack,
    });

    res.status(status >= 500 ? status : 200).json({ code: 1, msg });
  }
}

在响应拦截器中记录日志

unify-response.interceptor.ts

import {
  CallHandler,
  ExecutionContext,
  Inject,
  Injectable,
  NestInterceptor,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Request } from 'express';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import { Logger } from 'winston';
import { getReqMainInfo } from '../../utils/getReqMainInfo';

@Injectable()
export class UnifyResponseInterceptor implements NestInterceptor {
  constructor(
    @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger,
  ) {}

  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const ctx = context.switchToHttp();
    const req = ctx.getRequest<Request>();

    return next.handle().pipe(
      map(data => {
        this.logger.info('response', {
          responseData: data,
          req: getReqMainInfo(req),
        });
        return {
          code: 0,
          data,
          msg: '成功',
        };
      }),
    );
  }
}

应用全局中间件、过滤器以及拦截器

app.module.ts

import {
  MiddlewareConsumer,
  Module,
  NestModule,
  RequestMethod,
} from '@nestjs/common';
import { APP_FILTER } from '@nestjs/core';
import { WinstonModule } from 'nest-winston';
import * as winston from 'winston';
import 'winston-daily-rotate-file';
import UnifyExceptionFilter from './common/uinify-exception.filter';
import logger from './common/logger.middleware';
// ...

@Module({
  // ...
  imports: [
    // ...
    WinstonModule.forRoot({
     // ...
    }),
  ],
  providers: [
    // ...
    // 应用全局过滤器
    {
      provide: APP_FILTER,
      useClass: UnifyExceptionFilter,
    },
    // 应用拦截器
    {
      provide: APP_INTERCEPTOR,
      useClass: UnifyResponseInterceptor,
    },
  ],
})
export class AppModule implements NestModule {
  // 应用全局中间件
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(logger).forRoutes({ path: '*', method: RequestMethod.ALL });
  }
}

完成以上配置后,项目目录下就会包含访问及错误信息的日志文件。日志文件将每天自动归档压缩,超过 14 天的日志也将被自动删除。

引用

基于 Winston 实现 NestJS 应用日志服务
NestJS: Setting up file logging daily rotation with winston

Windows 相关知识操作及部分快捷键

之前机缘巧合,搜索了一下 Windows 相关知识,发现有一些知识和快捷键确实不了解,也从没注意到过,在此记录一下作为整理,如果你有其他关于 Windows 的相关知识和快捷键可以与我一同分享。

Windows 相关知识

1. 命令行访问带空格的目录时,必需要加引号,不然访问不到:

e.g. C:\>cd "Program Files\Java"

另最新版的 Windows 系统已经帮你处理了这块,按下 Tab 联想自动会加的,有时候就是用代码执行 bat 的时候需要注意这里。

2. Windows 中一些特殊单词不能作为文件名,例如 auxcom1com2prnconnul,如果你发现有软件用用户文件名作为配置文件夹名称,你可以把自己用户名改成上面那些单词,软件可能就会崩溃。

3. Windows 路径长度最多为 260 个字符。

4. Windows 创建一个没后缀名的文件需要在文件名称后面紧跟一个点,比如 .ignore. 系统会自动识别成 .ignore

5. 文件删除不掉提示被占用,可以通过资源监视器CPU关联句柄里搜索文件,然后结束进程。

6. 使用 PROGRA~1 代替 Program Files 。cmd 访问文件最快的办法是把文件用鼠标拖入 cmd 中。

7. Windows 软件闪退想找错误日志?运行里打开 eventvwr.exe

8. Windows 文件历史记录可以备份文件十分好用,Windows 自带的搜索可以设置搜索文件的内容(包括 TXT、Word、Excel 等文件内容)。

9. 按住 ctrl + shift + alt 再打开任务管理器,任务管理器会进入精简模式,便于在系统资源不足时使用任务管理器。任务管理器卡死崩溃,按 ctrl + shift + esc 可以让崩溃的任务管理器在 10 秒内重新启动。

10. 在开始菜单点关机重启时,按住 shift 键可以修改系统启动模式或进入高级恢复选项。

11. Windows 可以设置在重要操作时要求输入密码:组策略编辑器,Windows 组件,凭据用户界面—要求输入凭据的受信任路径,点击启用。系统 UAC 需要开最高。这样安装软件,修改系统重要设置都需要验证密码。

12. 电脑配置不高,你使用软件比较卡顿时,可以在任务管理器修改进程优先级。正常改为:高于正常。

13. 资源管理器中按住 Shift 键,再按鼠标右键会弹出带有“在此处打开 CMD/PowerShell 窗口”的菜单。

14. 选中文件上按住 Shift 点鼠标右键,菜单里会多出一项复制为路径。

15. Windows 下按住 alt 键双击文件夹会打开该文件夹的属性窗口。

16. 按住 Ctrl+Shift,再单击打开可执行程序,就会通过管理员模式打开。

17. 修改 hosts 文件时,可以按 Win + R 打开“运行”窗口,在输入框中输入 drivers 直接打开 C:\Windows\System32\drivers 目录,之后再自行打开 .\etc\hosts,比一层层目录点进去要省不少事。

18. Windows 系统盘下的 User 目录可以迁移到其他盘符中,具体操作可以看我之前发过的文章《改变 Windows 用户文件夹默认路径 C:/Users》。

Windows 快捷键

win + q (query) 搜索
win + w (write) 手写笔
win + e (explorer) 资源管理器
win + r (run) 运行
win + a (alert) 通知中心
win + s (search) 也是搜索
win + d (disappear) 老板键
win + f (feedback) 系统反馈
win + x 等同于右键点击开始菜单
win + c (cortana) 微软小娜
win + v 剪切板
win + h 语言输入
win + m (minimal) 最小化窗口
win + . emoji
win + ; emoji
win + i 设置
win + p (project) 投影
win + + 放大镜
win + d (desktop) 显示桌面
win + l (lock) 锁屏
win + t (taskbar) 任务栏上固定的应用
win + tab 虚拟桌面切换
win + ctrl + 左右键 切换虚拟桌面
win + shift + s 截图
ctrl + shift + Esc 任务管理器
ctrl + shift + Enter 以管理员权限启动
ctrl + l 激活地址栏,在地址栏中键入 PowerShell 即可自动打开已当前目录路径的 PowerShell
ctrl + w 关闭窗口

引用

Windows 下有哪些程序员平时不太了解,却很重要的知识?

改变 Windows 用户文件夹默认路径 C:/Users

Windows 默认的总用户文件夹总是会在系统盘下,如果你的系统盘为 C 盘,则为: C:\Users ,许多默认文件夹也都会放在这里:

  • 文档、桌面、下载、图片、视频等文件夹都默认在这里,这些文件夹倒是可以改变位置
  • AppData 文件夹默认在用户根目录下,存储了大部分软件的数据、配置,无法被改变位置
  • .config / .ssh / .config / scoop 等配置目录也在用户根目录下,无法改变位置
  • 许多软件的默认数据位置

系统盘符:\Users\用户名\AppData 里面一般有三个文件夹,分别是 Local / LocalLow / Roaming ,简单地来说,都是用来存放软件的配置文件和临时文件的,里面有很多以软件名称或软件公司命名的文件夹,还有用户帐户的配置文件。随着系统使用时间的增加和安装软件的增多, AppData 占用的空间会越来越大。

上面这些目录会导致系统盘占用很大,即使其中有部分可以手动指派其它路径,但是每次指定都很麻烦,重装系统时候备份也不方便(用户目录里有许多细碎的小文件,备份非常慢),还不如将用户目录迁出系统盘,所有软件都用默认路径,多省事。

另外,修改了用户路径后,当安装软件只为用户安装时,默认的安装路径也会到你的用户目录所在盘,大大节省了系统盘空间。

安装 Windows 的时候修改默认用户路径(推荐)

正常安装 Windows

当 Windows 连接到网络的时候有时 Sysprep 会失败,所以建议全程关闭网络连接安装系统。安装系统的方法不多做介绍。安装系统重启后停留在选择地区的配置界面。

进入 Audit Mode(审计模式)

在系统配置选择地区的界面,按下 Ctrl + Shift + F3 ,这时 Windows 会重启,进入 Audit Mode ,然后显示一个 System Preparation Tool(系统准备工具) ,点击取消,将它关闭。

新建 relocate.xml

现在你可以将电脑连接到网络了。

接下来我们要使用 System Preparation Tool (Sysprep) 工具来设置用户路径。这个工具会执行一个 xml 文件中的配置(也就是 relocate.xml)。我们现在只需要一个非常简单的 xml配置文件,只需包含以下内容:

  • Windows 的版本(32 或 64 位)
  • 用户文件夹的新路径(例如 D:/Users

新建 relocate.xml ,并使用记事本打开拷贝以下代码:

<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
	<settings pass="oobeSystem">
		<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
			<FolderLocations>
				<ProfilesDirectory>D:\Users</ProfilesDirectory>
			</FolderLocations>
		</component>
	</settings>
</unattend>
警告,在操作之前,请先读一下这个:
1. Windows 以字母来标识盘符,但是当安装了 Windows 重启之后,本来你想把用户目录安装到 d 盘,但这个盘符可能会发生改变,比如变成了 e 盘,这个时候就会失败,所以一定要确定好盘符。
2. xml 文件保存到磁盘根目录(不能是 C 盘),例如我把它保存到了 D:\relocate.xml
3. 部分计算机在 Audit Mode 下因为缺少驱动,键盘无法使用,可以借助其他计算机编写,并拷贝,也可以完全用鼠标操作完成,看个人能力。

运行 Sysprep

以管理员身份运行 cmd,首先确保已停止 WMP Network Sharing Service 服务:

net stop wmpnetworksvc

然后运行以下命令:

%windir%\system32\sysprep\sysprep.exe /oobe /reboot /unattend:d:\relocate.xml

上述命令告诉系统从 Windows\System32\Sysprep 运行 Sysprep,执行 D:/relocate.xml 中的指令,为 OOBE (the firlst boot of newly installed Windows) 重启准备系统,最后重启。

完成

完成上述操作后,自动重启进入系统,检查 User 目录已经移动到了 D 盘。

在已经安装好的 Windows 系统上迁移用户目录

警告:操作之前,一定要先创建一个系统映像,做好备份。
对一个 OEM 预先安装的 Windows 使用 Sysprep 是非常危险的。电脑厂商可能有他们自己的 unattended answer file,这样可能就会忽略掉你的 unattended file。在这个过程中可能会出各种错误,所以不建议操作。
如果中途出错了,你的备份文件可以帮助你恢复。
这个操作非常有可能导致你的电脑恢复出厂设置。
警告****1703 或者更高版本,请不要禁用已存在的用户!!!
在 Win10 1703 或更高版本上,千万不要禁用现有用户,因为禁用现有用户可能会让你无法登录 Windows,进而需要重装。

新建 relocate.xml

按照上面说过的步骤新建一个 relocate.xml 文件。

运行 Sysprep

按照上面说过的步骤运行 Sysprep

OOBE

虽然你已经安装了 Windows,但是在 Sysprep 运行之后 OOBE 仍然会运行,这意味着你的电脑会经历初始化程序。

这里有两点需要注意:

  • Windows 要求你输入产品密钥,但是不需要去输入,单击跳过就可以了;
  • 之前的账户还会存在,但是 OOBE 会要求新建一个用户,如果新建的这个用户和已存在的用户名字相同,那就会发生错误。只需要新建一个随意的账户,之后,再把它删掉就可以了;

引用

Windows 如何删除右键菜单中的 “Git Gui Here”和“Git Bash Here”

今天重新安装了 Git 后,发现右击鼠标右侧多出了两个选项“Git Gui Here”和“Git Bash Here”。虽然这样证明我的 Git 已经成功安装了,但还是影响使用感受,遂上网寻找了一下相关的解决方案。

手动修改注册表

  1. Win + R 调出“运行”窗口,在搜索框中输入“regedit”打开注册表编辑器;
  2. 在打开的注册表中通过以下路径进行查找: Computer\HKEY_CLASSES_ROOT\Directory\Background\shell 。在下方就可以看到 git_guigit_shell 这两项内容,将其删除即可。
  3. 关闭注册表之后,在桌面上右击鼠标就能看到 “Git Gui Here”和“Git Bash Here”选项就已经被删除了。

直接使用管理员 CMD(命令提示符)执行删除

如果上述方法比较繁琐,可以尝试使用具有管理员权限的 CMD(命令提示符) 执行以下两条语句:

reg delete "HKEY_CLASSES_ROOT\Directory\Background\shell\git_gui" /f
reg delete "HKEY_CLASSES_ROOT\Directory\Background\shell\git_shell" /f