技术便笺
因为我很懒,就直接把列表放上来好了….
一些配置
Adding Password Change Link to the RD Web Access Login Form You can add a link to the password change form directly to the Remote Desktop WebAccess sign-in form. This will allow users to change their password any time without waiting till it expires. Insert a link to the password.aspx file into the RDWeb sign-in page (create a backup copy of the password.aspx file before editing). On the RDWeb server, find and open the file C:\Windows\Web\RDWeb\Pages\en-US\login.aspx in any text editor (I prefer Notepad++); Go to line 429 (In Windows Server 2022, it is located after the following HTML block <tr id="trPasswordExpiredNoChange" <%=strErrorMessageRowStyle%> > … </tr> ) and paste the following code: <!-- Begin: Add Change Password Link --> <tr> <td align="right"> <a href="password.aspx" title="Change AD User Password">Click here </a>to change your password. </td> </tr> <!-- End: Add Change Password Link -->
Hyper-V 使用 GPU-PV
施工中
https://www.reddit.com/r/HyperV/comments/vph5lw/windows_server_2022_gpup_virtualization_working/
https://github.com/jamesstringerparsec/Easy-GPU-PV/
https://github.com/jamesstringerparsec/Easy-GPU-PV/issues/65
https://superuser.com/questions/647638/create-folder-on-system32-driverstore-filerepository
https://www.tenforums.com/virtualization/195745-tutorial-passing-through-gpu-hyper-v-guest-vm.html
- add-gpu-pv.ps1
Param ( [string]$VMName = "TEST", [string]$GPUName = "AUTO", [string]$Hostname = $ENV:Computername, [decimal]$GPUResourceAllocationPercentage = 100 ) Function Add-VMGpuPartitionAdapterFiles { param( [string]$hostname = $ENV:COMPUTERNAME, [string]$DriveLetter, [string]$GPUName ) If (!($DriveLetter -like "*:*")) { $DriveLetter = $Driveletter + ":" } If ($GPUName -eq "AUTO") { $PartitionableGPUList = Get-WmiObject -Class "Msvm_PartitionableGpu" -ComputerName $env:COMPUTERNAME -Namespace "ROOT\virtualization\v2" $DevicePathName = $PartitionableGPUList.Name | Select-Object -First 1 $GPU = Get-PnpDevice | Where-Object {($_.DeviceID -like "*$($DevicePathName.Substring(8,16))*") -and ($_.Status -eq "OK")} | Select-Object -First 1 $GPUName = $GPU.Friendlyname $GPUServiceName = $GPU.Service } Else { $GPU = Get-PnpDevice | Where-Object {($_.Name -eq "$GPUName") -and ($_.Status -eq "OK")} | Select-Object -First 1 $GPUServiceName = $GPU.Service } # Get Third Party drivers used, that are not provided by Microsoft and presumably included in the OS Write-Host "INFO : Finding and copying driver files for $GPUName to VM. This could take a while..." $Drivers = Get-WmiObject Win32_PNPSignedDriver | where {$_.DeviceName -eq "$GPUName"} New-Item -ItemType Directory -Path "$DriveLetter\windows\system32\HostDriverStore" -Force | Out-Null #copy directory associated with sys file $servicePath = (Get-WmiObject Win32_SystemDriver | Where-Object {$_.Name -eq "$GPUServiceName"}).Pathname $ServiceDriverDir = $servicepath.split('\')[0..5] -join('\') $ServicedriverDest = ("$driveletter" + "\" + $($servicepath.split('\')[1..5] -join('\'))).Replace("DriverStore","HostDriverStore") if (!(Test-Path $ServicedriverDest)) { Copy-item -path "$ServiceDriverDir" -Destination "$ServicedriverDest" -Recurse } # Initialize the list of detected driver packages as an array $DriverFolders = @() foreach ($d in $drivers) { $DriverFiles = @() $ModifiedDeviceID = $d.DeviceID -replace "\\", "\\" $Antecedent = "\\" + $hostname + "\ROOT\cimv2:Win32_PNPSignedDriver.DeviceID=""$ModifiedDeviceID""" $DriverFiles += Get-WmiObject Win32_PNPSignedDriverCIMDataFile | where {$_.Antecedent -eq $Antecedent} $DriverName = $d.DeviceName $DriverID = $d.DeviceID if ($DriverName -like "NVIDIA*") { New-Item -ItemType Directory -Path "$driveletter\Windows\System32\drivers\Nvidia Corporation\" -Force | Out-Null } foreach ($i in $DriverFiles) { $path = $i.Dependent.Split("=")[1] -replace '\\\\', '\' $path2 = $path.Substring(1,$path.Length-2) $InfItem = Get-Item -Path $path2 $Version = $InfItem.VersionInfo.FileVersion If ($path2 -like "c:\windows\system32\driverstore\*") { $DriverDir = $path2.split('\')[0..5] -join('\') $driverDest = ("$driveletter" + "\" + $($path2.split('\')[1..5] -join('\'))).Replace("driverstore","HostDriverStore") if (!(Test-Path $driverDest)) { Copy-item -path "$DriverDir" -Destination "$driverDest" -Recurse } } Else { $ParseDestination = $path2.Replace("c:", "$driveletter") $Destination = $ParseDestination.Substring(0, $ParseDestination.LastIndexOf('\')) if (!$(Test-Path -Path $Destination)) { New-Item -ItemType Directory -Path $Destination -Force | Out-Null } Copy-Item $path2 -Destination $Destination -Force } } } } $VM = Get-VM -VMName $VMName $VHD = Get-VHD -VMId $VM.VMId If ($VM.state -eq "Running") { [bool]$state_was_running = $true } if ($VM.state -ne "Off"){ "Attemping to shutdown VM..." Stop-VM -Name $VMName -Force } While ($VM.State -ne "Off") { Start-Sleep -s 3 "Waiting for VM to shutdown - make sure there are no unsaved documents..." } "Mounting Drive..." $DriveLetter = (Mount-VHD -Path $VHD.Path -PassThru | Get-Disk | Get-Partition | Get-Volume | Where-Object {$_.DriveLetter} | ForEach-Object DriveLetter) "Copying GPU Files - this could take a while..." Add-VMGPUPartitionAdapterFiles -hostname $Hostname -DriveLetter $DriveLetter -GPUName $GPUName "Dismounting Drive..." Dismount-VHD -Path $VHD.Path function Assign-VMGPUPartitionAdapter { $PartitionableGPUList = Get-WmiObject -Class "Msvm_PartitionableGpu" -ComputerName $env:COMPUTERNAME -Namespace "ROOT\virtualization\v2" if ($GPUName -eq "AUTO") { $DevicePathName = $PartitionableGPUList.Name[0] Add-VMGpuPartitionAdapter -VMName $VMName } else { $DeviceID = ((Get-WmiObject Win32_PNPSignedDriver | where {($_.Devicename -eq "$GPUNAME")}).hardwareid).split('\')[1] $DevicePathName = ($PartitionableGPUList | Where-Object name -like "*$deviceid*").Name Add-VMGpuPartitionAdapter -VMName $VMName -InstancePath $DevicePathName } [float]$devider = [math]::round($(100 / $GPUResourceAllocationPercentage),2) Set-VMGpuPartitionAdapter -VMName $VMName -MinPartitionVRAM ([math]::round($(1000000000 / $devider))) -MaxPartitionVRAM ([math]::round($(1000000000 / $devider))) -OptimalPartitionVRAM ([math]::round($(1000000000 / $devider))) Set-VMGPUPartitionAdapter -VMName $VMName -MinPartitionEncode ([math]::round($(18446744073709551615 / $devider))) -MaxPartitionEncode ([math]::round($(18446744073709551615 / $devider))) -OptimalPartitionEncode ([math]::round($(18446744073709551615 / $devider))) Set-VMGpuPartitionAdapter -VMName $VMName -MinPartitionDecode ([math]::round($(1000000000 / $devider))) -MaxPartitionDecode ([math]::round($(1000000000 / $devider))) -OptimalPartitionDecode ([math]::round($(1000000000 / $devider))) Set-VMGpuPartitionAdapter -VMName $VMName -MinPartitionCompute ([math]::round($(1000000000 / $devider))) -MaxPartitionCompute ([math]::round($(1000000000 / $devider))) -OptimalPartitionCompute ([math]::round($(1000000000 / $devider))) } "Assigning GPU-P Adapter" Assign-VMGPUPartitionAdapter If ($state_was_running){ "Previous State was running so starting VM..." Start-VM $VMName } "Done..."
Hyper-V Guide Install windows server 22 host, and update to latest build, install Hyper-V Role. (21H2, OS Build: 20348.803 or later / Cumulative update KB5014665)
We'll be using Jamesstringerparsec Easy-GPU-PV's guide with a few tweaks, so download and extract the package to a folder. GitHub - jamesstringerparsec/Easy-GPU-PV: A Project dedicated to making GPU Partitioning on Windows easier!
Run powershell ISE as an admin and set Execution policy to unrestricted Set-ExecutionPolicy -ExecutionPolicy Unrestricted -force
Once done, go to File > Open > and open CopyFilesToVM.ps1
Firstly, modify the script to add your server info. Take a look at the Github values to understand what each settings does and which should not be changed. The settings are made with Win10/11 in mind. Below are the settings that must be changed to work with WinServer:
Edition = to find out the number for your Windows edition, open a separate powershell window and run the following script after mounting your Server ISO to a drive letter: dism /get-wiminfo /wimfile:<Drive Letter>:\\sources\\install.wim (this can also be done with native POSH cmdlets, Black V using Get-WindowsImage -ImagePath F:\sources\install.win) Once you run the command there will be an index number for every windows version available. Choose your specific version and set that number as the Edition Value.
GPUName = Leave as auto if the GPU you are virtualising is the only one available. (Personally I'd manually name it saves issues later on, Black V)
Once this is done, run the script. It should go through the creating on the VM, but will fail when trying to launch it. In my case, the error was somewhere along the lines of:
GPU Partition (Instance ID 69E7E377-A066-41D6-A03B-E610AC30DAA6): Failed to Power on with Error
'.'.Insufficient system resources exist to complete the requested service
'WS22PLEX' failed to start. (Virtual machine ID CAED9896-6895-4541-AC43-B25856D3B385)
'WS22PLEX' GPU Partition (Instance ID 69E7E377-A066-41D6-A03B-E610AC30DAA6): Failed to Power on with Error
'Insufficient system resources exist to complete the requested service.' (0x800705AA). (Virtual machine ID CAED9896-6895-4541-AC43-B25856D3B385)
Could not allocate a GPU partition as no GPU devices are compliant with currently set group policy. See HyperV\RequireSecureDeviceAssignment and HyperV\RequireSupportedDeviceAssignment for more details.
To get around this, you need to create 2 keys in Reg edit.
HKLM:\SOFTWARE\Policies\Microsoft\Windows\HyperV“ -Name “RequireSecureDeviceAssignment” -Type DWORD -Value 0
HKLM:\SOFTWARE\Policies\Microsoft\Windows\HyperV” -Name “RequireSupportedDeviceAssignment” -Type DWORD -Value 0
I closed off MMC.exe from Task Manager before attempting to run the VM again. Try to launch the VM again by running the following command in Powershell: Start-VM Server123 (Replace “Server123” with your recently created guest server name).
Your server should now boot up with no error. I installed drivers in the guest and tested by running a 4K youtube video, and watched the resource spike up on the host machine's task manager.
Notes:
Make sure that you install GPU drivers on the host machine before doing any of the above.
Make sure to install GPU drivers on the guest VM when after creation and booting into it.
Normally, GPU resources are not visible in the guest VM.
Check Device manager to make sure the GPU shows up and is enabled. If it isn't, you need to extract the drivers from the host machine and re-assign them to the VM.
See the github link
Normal NTFS Permisions on folder C:\Windows\System32\DriverStore\FileRepository\ are System - Full Control, and Everyone - Read & Execute.
I you really want to copy into this directory you can do the following:
Right click the folder, click Properties Click the Security tab Click the Edit button. Now add your account and give it Full Control Click Ok Click Yes at the “Windows Security”-prompt At the “Error Applying Security”-prompt click Continue once and Cancel at the next Click Ok at the “Windows Security”-prompt You can now copy files/folder into this directory.
To get control over all the other directories you could “Get Ownership” of this folder but that's not recommended. (you already have read access of those)
Solutions for existing VM
Steps:
Test to see if your GPU can be partitioned at all. On the Host, open a Powershell prompt as administrator. Then run: Get-VMPartitionableGpu (win10) or Get-VMHostPartitionableGpu (win11)
Open up Device Manager on the guest VM, and check the Display Adapters. You will see that your GPU is NOT enabled. Then shut down the VM.
Go to this link: GitHub - jamesstringerparsec/Easy-GPU-PV: A Project dedicated to making GPU Partitioning on Windows easier! You can download the full repo if you want. But you only need these two files: Add-VMGpuPartitionAdapterFiles.psm1 Update-VMGpuPartitionDriver.ps1
From the admin powershell console, run this command: .\Update-VMGpuPartitionDriver.ps1 -VMName “Name of your VM” -GPUName “AUTO” Just edit that command with the name or your VM. GPU “AUTO” will automatically determine your GPU. These scripts will find all the driver files from your host machine, and copy the files to the VM. This can take some time.
With the VM still off, create a new .ps1 powershell file on the host, and paste in this code: Code:
$vm = "Name of your VM" if (Get-VMGpuPartitionAdapter -VMName $vm -ErrorAction SilentlyContinue) { Remove-VMGpuPartitionAdapter -VMName $vm } Set-VM -GuestControlledCacheTypes $true -VMName $vm Set-VM -LowMemoryMappedIoSpace 1Gb -VMName $vm Set-VM -HighMemoryMappedIoSpace 32Gb -VMName $vm Add-VMGpuPartitionAdapter -VMName $vm
This script will enable the GPU partitioning for your VM, and turn on some required settings.
Edit the first line and again put the name of your VM. Then run this script file in your powershell prompt by preceeding the filename with .\ just like you did with the previous script above.
Now we should have the drivers copied into the VM, and the GPU partitioning feature enabled. You can now turn on the VM, and go back to Device Manager and see if your GPU is now shown under Display Adapters
rTorrent with selfsigned SSL certs
openssl s_client -connect <server.tld>:443 | tee <server.tld>_out_cert
openssl x509 -inform PEM -in <server.tld>_out_cert -text -out <server.tld>_out_cert.pem
mv <server.tld>_out_cert.pem /etc/ssl/certs
cd /etc/ssl/certs
c_rehash
vi rtorrent.rc, add config below, and restart rtorrent.
# Self_signed Certs network.http.capath = /etc/ssl/certs/
导出Word中全部批注
Word 中 Alt+F11,插入模块,粘贴以下 VBA 脚本,运行。活动文档中的全部批注会被放入新的 word 文件中1)。
注意,VBA 无法处理批注中的图片,请留意。
Sub exportcomments() Dim s As String Dim cmt As Word.Comment Dim doc As Word.Document For Each cmt In ActiveDocument.Comments s = s & cmt.Index & "|" & cmt.Author & "|" & cmt.Range.Text & "|" & cmt.Date & vbCr Next Set doc = Documents.Add doc.Range.Text = s End Sub
其他拓展可见 https://docs.microsoft.com/en-us/office/vba/api/word.comment
Synology 上部署 Wekan
在 Portainer 中创建 Stack,粘贴如下内容,适应性修改相关信息。记得在存储池中创建相应文件夹,并赋予 System 读写权限2)。
version: '2' services: wekandb: image: mongo:4.4 container_name: wekan-db restart: always expose: - 27017 volumes: - /volume1/docker/wekan/db:/data/db - /volume1/docker/wekan/db:/dump wekan: image: wekanteam/wekan container_name: wekan restart: always ports: - 38080:8080 environment: - MONGO_URL=mongodb://wekandb:27017/wekan - MAIL_URL=smtps://apikey:xxx@smtp.sendgrid.net:465/ - MAIL_FROM="Wekan Notifications <noreply.wekan@xxx.yyy>" - ROOT_URL=https://xxx.yyy - BROWSER_POLICY_ENABLED=true depends_on: - wekandb volumes: - /etc/localtime:/etc/localtime:ro - /volume1/docker/wekan/app:/data volumes: wekan-files: driver: local wekan-db: driver: local wekan-db-dump: driver: local networks: wekan-tier: driver: bridge