如何使用 Powershell 更改“我的电脑”桌面图标?

3

我正在学习一些Shell脚本,因为测试自动化似乎越来越流行。

我的Powershell掌握得比较通用。我当前的目标是更改“我的电脑”桌面图标。

在Microsoft Windows 10操作系统中,有一些我尚未使用Powershell进行操作的内容。我希望也许一些比我更有经验的作者能够帮助我达成这个目标。

我刚刚测试了两个片段,令人惊讶的是它们在第一次尝试时都成功运行了。

第一个脚本可以称为Create_Shortcut.PS1,它为命令行预处理系统创建一个桌面图标,其中可以运行批处理文件。

# Creates the command-line desktop icon.

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

$TargetFile = "C:\Windows\System32\Cmd.Exe"

$ShortcutFile = "\\ISXPFV01.hd00.example.com\us_qv2_dem_user_data_pool_nra$\EE65037.HD00\Desktop\Command-Line.Lnk"

$WScriptShell = New-Object -COMObject WScript.Shell

$Shortcut = $WScriptShell.CreateShortcut($ShortcutFile)

$Shortcut.TargetPath = $TargetFile

$Shortcut.Save()

第二个脚本可能被称为Rename_My_Computer.PS1,它会重命名桌面上的“我的电脑”图标。
# Changes the My Computer desktop icon name from "This PC" to "VSDC0365".

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

$My_Computer = 17

$Shell = New-Object -COMObject Shell.Application

$NSComputer = $Shell.Namespace($My_Computer)

$NSComputer.Self.Name = $Env:COMPUTERNAME

对于比我更有Powershell经验的人来说,我感兴趣的内容可能非常简单。我需要通过指定路径来更改“我的电脑”桌面图标。

由于我还没有达到这个目标,所以任何关于这个主题的帮助都将不胜感激。

感谢阅读。

@Theo的评论后更新:

一个令人惊讶的新代码片段,可以生成“我的电脑”桌面图标:

# HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel\
# {20D04FE0-3AEA-1069-A2D8-08002B30309D}
# 0 = show
# 1 = hide

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

$Path = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel"

$Name = "{20D04FE0-3AEA-1069-A2D8-08002B30309D}"

$Exist = "Get-ItemProperty -Path $Path -Name $Name"

if ($Exist)
{
    Set-ItemProperty -Path $Path -Name $Name -Value 0
}
Else
{
    New-ItemProperty -Path $Path -Name $Name -Value 0
}

现在,我需要以某种编程方式按下F5来刷新桌面视图,并在设置他在评论中提到后进行操作。
另一个与刷新相关的更新:
另一个出人意料可行的片段,可以刷新桌面视图:
# Refresh Desktop Ability

$Definition = @'

    [System.Runtime.InteropServices.DllImport("Shell32.dll")]

    private static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);

    public static void Refresh() {
        SHChangeNotify(0x8000000, 0x1000, IntPtr.Zero, IntPtr.Zero);
    }
'@

Add-Type -MemberDefinition $Definition -Namespace WinAPI -Name Explorer

# Refresh desktop icons
[WinAPI.Explorer]::Refresh()

现在所有需要做的就是在刷新之前以某种方式更改“我的电脑”桌面图标。

与获取注册表项所有权相关的更新:

很棘手。我不知道它会变得如此复杂。

目前,它会出现以下错误消息而失败:

PS Y:\> Y:\Digitization\Powershell\The_My_Computer_Desktop_Icon\Change_Registry_Key.PS1
True
Exception calling "OpenSubKey" with "3" argument(s): "Requested registry access is not allowed."
At Y:\Digitization\Powershell\The_My_Computer_Desktop_Icon\Change_Registry_Key.PS1:139 char:1
+ $RegKey = [Microsoft.Win32.Registry]::ClassesRoot.OpenSubKey(         ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : SecurityException

以下是 Change_Registry_Key.PS1 文件的内容:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

Function Enable-Privilege {
  Param(
  ## The privilege to adjust.
  [ValidateSet(
      "SeAssignPrimaryTokenPrivilege"
    , "SeAuditPrivilege"
    , "SeBackupPrivilege"
    , "SeChangeNotifyPrivilege"
    , "SeCreateGlobalPrivilege"
    , "SeCreatePagefilePrivilege"
    , "SeCreatePermanentPrivilege"
    , "SeCreateSymbolicLinkPrivilege"
    , "SeCreateTokenPrivilege"
    , "SeDebugPrivilege"
    , "SeEnableDelegationPrivilege"
    , "SeImpersonatePrivilege"
    , "SeIncreaseBasePriorityPrivilege"
    , "SeIncreaseQuotaPrivilege"
    , "SeIncreaseWorkingSetPrivilege"
    , "SeLoadDriverPrivilege"
    , "SeLockMemoryPrivilege"
    , "SeMachineAccountPrivilege"
    , "SeManageVolumePrivilege"
    , "SeProfileSingleProcessPrivilege"
    , "SeRelabelPrivilege"
    , "SeRemoteShutdownPrivilege"
    , "SeRestorePrivilege"
    , "SeSecurityPrivilege"
    , "SeShutdownPrivilege"
    , "SeSyncAgentPrivilege"
    , "SeSystemEnvironmentPrivilege"
    , "SeSystemProfilePrivilege"
    , "SeSystemtimePrivilege"
    , "SeTakeOwnershipPrivilege"
    , "SeTcbPrivilege"
    , "SeTimeZonePrivilege"
    , "SeTrustedCredManAccessPrivilege"
    , "SeUndockPrivilege"
    , "SeUnsolicitedInputPrivilege")]
    $Privilege
    ## The process on which to adjust the privilege. Defaults to the current process.
  , $ProcessId = $Pid
    ## Switch to disable the privilege, rather than enable it.
  , [Switch] $Disable
  )

  $Definition = @'
    using System;
    using System.Runtime.InteropServices;

    public class AdjPriv
    {
       [DllImport(  "advapi32.dll"
                  , ExactSpelling = true
                  , SetLastError = true)]

       internal static extern bool AdjustTokenPrivileges(  IntPtr htok
                                                         , bool disall
                                                         , ref TokPriv1Luid newst
                                                         , int len
                                                         , IntPtr prev
                                                         , IntPtr relen);

       [DllImport(  "advapi32.dll"
                  , ExactSpelling = true
                  , SetLastError = true)]

       internal static extern bool OpenProcessToken(  IntPtr h
                                                    , int acc
                                                    , ref IntPtr phtok);

       [DllImport(  "advapi32.dll"
                  , SetLastError = true)]

       internal static extern bool LookupPrivilegeValue(  string host
                                                        , string name
                                                        , ref long pluid);

       [StructLayout(  LayoutKind.Sequential
                     , Pack = 1)]

       internal struct TokPriv1Luid
       {
          public int Count;
          public long Luid;
          public int Attr;
       }

       internal const int SE_PRIVILEGE_ENABLED    = 0x00000002;
       internal const int SE_PRIVILEGE_DISABLED   = 0x00000000;
       internal const int TOKEN_QUERY             = 0x00000008;
       internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;

       public static bool EnablePrivilege(  long processHandle
                                          , string privilege
                                          , bool disable)
       {
           bool retVal;
           TokPriv1Luid tp;
           IntPtr hproc = new IntPtr(processHandle);
           IntPtr htok = IntPtr.Zero;
           retVal = OpenProcessToken(  hproc
                                     , TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY
                                     , ref htok);
           tp.Count = 1;
           tp.Luid = 0;
           if(disable)
           {
               tp.Attr = SE_PRIVILEGE_DISABLED;
           }
           else
           {
               tp.Attr = SE_PRIVILEGE_ENABLED;
           }
           retVal = LookupPrivilegeValue(  null
                                         , privilege
                                         , ref tp.Luid);
           retVal = AdjustTokenPrivileges(  htok
                                          , false
                                          , ref tp
                                          , 0
                                          , IntPtr.Zero
                                          , IntPtr.Zero);
           return retVal;
    }
  }
'@

$ProcessHandle = (Get-Process -Id $ProcessId).Handle
$Type = Add-Type $Definition -PassThru
$Type[0]::EnablePrivilege($processHandle, $Privilege, $Disable)
}

Enable-Privilege SeTakeOwnershipPrivilege

# Change Owner to the local Administrators group.
$RegKey = [Microsoft.Win32.Registry]::ClassesRoot.OpenSubKey(               `
            "CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}"                  `
          , [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree  `
          , [System.Security.AccessControl.RegistryRights]::TakeOwnership)
$RegACL = $RegKey.GetAccessControl()
$RegACL.SetOwner([System.Security.Principal.NTAccount]"Administrators")
$RegKey.SetAccessControl($RegACL)

# Change Permissions for the local Administrators group.
$RegKey = [Microsoft.Win32.Registry]::ClassesRoot.OpenSubKey(               `
            "CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}"                  `
          , [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree  `
          , [System.Security.AccessControl.RegistryRights]::ChangePermissions)
$RegACL = $RegKey.GetAccessControl()
$RegRule = New-Object System.Security.AccessControl.RegistryAccessRule(     `
             "Administrators"                                               `
           , "FullControl"                                                  `
           , "ContainerInherit"                                             `
           , "None"                                                         `
           , "Allow")
$RegACL.SetAccessRule($RegRule)
$RegKey.SetAccessControl($RegACL)

更新:关于尝试接管注册表键的另一次尝试的相关内容:

这是另一个代码片段的内容,名为Change_Registry_Key.2.PS1

#Define HKCR
New-PSDrive -Name       HKCR7              `
            -PSProvider Registry           `
            -Root       HKEY_CLASSES_ROOT

#Set $Path HKCR Key Path
$Path = "HKCR:\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}"

#Set $Path Permissions
$ACL = Get-ACL $Path

$Rule = New-Object System.Security.AccessControl.RegistryAccessRule ( `
            "<domain>\<username>"                                     `
          , "FullControl"                                             `
          , "Allow")

$ACL.SetAccessRule($Rule)

$ACL | Set-ACL -Path $path

#Set HKCR 'Attributes' Key Value
Set-ItemProperty -Path   $Path        `
                 -Name   Attributes   `
                 -Value  b0940064

以下是在控制台区域出现的错误:

PS Y:\> Y:\Digitization\Powershell\The_My_Computer_Desktop_Icon\Change_Registry_Key.2.PS1

Name           Used (GB)     Free (GB) Provider      Root                           
----           ---------     --------- --------      ----                           
HKCR7                                  Registry      HKEY_CLASSES_ROOT              
Exception calling "SetAccessRule" with "1" argument(s): "Some or all identity refere
nces could not be translated."
At Y:\Digitization\Powershell\The_My_Computer_Desktop_Icon\Change_Registry_Key.2.PS1
:17 char:1
+ $ACL.SetAccessRule($Rule)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : IdentityNotMappedException
 
Set-ACL : Requested registry access is not allowed.
At Y:\Digitization\Powershell\The_My_Computer_Desktop_Icon\Change_Registry_Key.2.PS1
:19 char:8
+ $ACL | Set-ACL -Path $path
+        ~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : PermissionDenied: (HKEY_CLASSES_RO...8-08002B30309D}: 
   String) [Set-Acl], SecurityException
    + FullyQualifiedErrorId : System.Security.SecurityException,Microsoft.PowerShel 
   l.Commands.SetAclCommand
 
Set-ItemProperty : Requested registry access is not allowed.
At Y:\Digitization\Powershell\The_My_Computer_Desktop_Icon\Change_Registry_Key.2.PS1
:22 char:1
+ Set-ItemProperty -Path   $Path        `
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : PermissionDenied: (HKEY_CLASSES_RO...8-08002B30309D}: 
   String) [Set-ItemProperty], SecurityException
    + FullyQualifiedErrorId : System.Security.SecurityException,Microsoft.PowerShel 
   l.Commands.SetItemPropertyCommand

关于 @Theo 的重命名“我的电脑”桌面图标的第二个版本的更新:

这个版本对我来说还没有生效。

它的测试非常简单:

  • 我手动将“我的电脑”桌面图标重命名为Fifi
  • 然后运行这个片段;
  • 然后手动刷新桌面视图。

虽然我希望“我的电脑”桌面图标会被重命名回工作笔记本,但它的名称仍然固定为Fifi

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

#Requires -RunAsAdministrator

Function Enable-Privilege {
    [CmdletBinding(  ConfirmImpact         = 'low'
                   , SupportsShouldProcess = $false)]
    [OutputType('System.Boolean')]
    Param(
        [Parameter(  Mandatory = $true
                   , Position  = 0)]
        [ValidateSet(  "SeAssignPrimaryTokenPrivilege"
                     , "SeAuditPrivilege"
                     , "SeBackupPrivilege"
                     , "SeChangeNotifyPrivilege"
                     , "SeCreateGlobalPrivilege"
                     , "SeCreatePagefilePrivilege"
                     , "SeCreatePermanentPrivilege"
                     , "SeCreateSymbolicLinkPrivilege"
                     , "SeCreateTokenPrivilege"
                     , "SeDebugPrivilege"
                     , "SeEnableDelegationPrivilege"
                     , "SeImpersonatePrivilege"
                     , "SeIncreaseBasePriorityPrivilege"
                     , "SeIncreaseQuotaPrivilege"
                     , "SeIncreaseWorkingSetPrivilege"
                     , "SeLoadDriverPrivilege"
                     , "SeLockMemoryPrivilege"
                     , "SeMachineAccountPrivilege"
                     , "SeManageVolumePrivilege"
                     , "SeProfileSingleProcessPrivilege"
                     , "SeRelabelPrivilege"
                     , "SeRemoteShutdownPrivilege"
                     , "SeRestorePrivilege"
                     , "SeSecurityPrivilege"
                     , "SeShutdownPrivilege"
                     , "SeSyncAgentPrivilege"
                     , "SeSystemEnvironmentPrivilege"
                     , "SeSystemProfilePrivilege"
                     , "SeSystemtimePrivilege"
                     , "SeTakeOwnershipPrivilege"
                     , "SeTcbPrivilege"
                     , "SeTimeZonePrivilege"
                     , "SeTrustedCredManAccessPrivilege"
                     , "SeUndockPrivilege"
                     , "SeUnsolicitedInputPrivilege")]
        [String]$Privilege

      , [Parameter(Position = 1)]
        $ProcessId = $PID

      , [switch]$Disable
        )


        Add-Type -TypeDefinition @'
using System;
using System.Runtime.InteropServices;

public class Privilege {
    [DllImport(  "advapi32.dll"
               , ExactSpelling = true
               , SetLastError  = true)]

    internal static extern bool AdjustTokenPrivileges(
         IntPtr htok
       , bool   disall
       , ref    TokPriv1Luid newst
       , int    len
       , IntPtr prev
       , IntPtr relen);

    [DllImport(  "advapi32.dll"
               , ExactSpelling = true
               , SetLastError  = true)]

    internal static extern bool OpenProcessToken(  IntPtr h
                                                 , int    acc
                                                 , ref    IntPtr phtok);

    [DllImport(  "advapi32.dll"
               , SetLastError = true)]

    internal static extern bool LookupPrivilegeValue(  string host
                                                     , string name
                                                     , ref    long pluid);

    [StructLayout(  LayoutKind.Sequential
                  , Pack = 1)]

    internal struct TokPriv1Luid {
        public int  Count;
        public long Luid;
        public int  Attr;
    }

    internal const int SE_PRIVILEGE_ENABLED    = 0x00000002;
    internal const int SE_PRIVILEGE_DISABLED   = 0x00000000;
    internal const int TOKEN_QUERY             = 0x00000008;
    internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;

    public static bool EnablePrivilege(  long   processHandle
                                       , string privilege
                                       , bool   disable) {
        bool         retVal;
        TokPriv1Luid tp;
        IntPtr       hproc = new IntPtr(processHandle);
        IntPtr       htok  = IntPtr.Zero;
        retVal = OpenProcessToken(  hproc
                                  , TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY
                                  , ref htok);
        tp.Count = 1;
        tp.Luid  = 0;
        if(disable) {
            tp.Attr = SE_PRIVILEGE_DISABLED;
        }
        else {
            tp.Attr = SE_PRIVILEGE_ENABLED;
        }
        retVal = LookupPrivilegeValue(  null
                                      , privilege
                                      , ref tp.Luid);
        retVal = AdjustTokenPrivileges(  htok
                                       , false
                                       , ref tp
                                       , 0
                                       , IntPtr.Zero
                                       , IntPtr.Zero);
        return retVal;
    }
}
'@

    try {
        $proc   = Get-Process -Id $ProcessId -ErrorAction Stop
        $name   = $proc.ProcessName
        $handle = $proc.Handle
        $action = if ($Disable) { 'Disabling' } else { 'Enabling' }
        Write-Verbose (  "{0} privilege '{1}' for process {2}" -f $action `
                       , $Privilege                                       `
                       , $name)
        [Privilege]::EnablePrivilege(  $handle         `
                                     , $Privilege      `
                                     , [bool]$Disable)
    }
    catch {
        throw
    }
}

################################################################
# Step 1: Give the current process the SeTakeOwnershipPrivilege.
################################################################

    $null = Enable-Privilege -Privilege SeTakeOwnershipPrivilege -Verbose

##############################################################
# Step 2: change Owner to the local Administrators group
##############################################################

# Better not use the string "Administrators", because this
# might have a different name in other cultures.
#
# $RegACL.SetOwner([System.Security.Principal.NTAccount]"Administrators")
#
# Use the Well-Known SID instead.
# Local Administrators Group.
$Administrators = `
   [System.Security.Principal.SecurityIdentifier]::new('S-1-5-32-544')

$RegKey = [Microsoft.Win32.Registry]::ClassesRoot.OpenSubKey(        `
     "CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}"                  `
   , [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree  `
   , [System.Security.AccessControl.RegistryRights]::TakeOwnership)

$RegACL = $RegKey.GetAccessControl()
$RegACL.SetOwner($Administrators)
$RegKey.SetAccessControl($RegACL)

##############################################################
# Step 3:  Give the Local Administrators Group Full Control.
##############################################################

# Refresh the A.C.L.
$RegACL = $RegKey.GetAccessControl()

# Test if there is a Deny rule in the ACL
# for Administrators and, if so, remove that rule.
$RegACL.GetAccessRules(                                     `
         $true                                              `
       , $true                                              `
       , [System.Security.Principal.SecurityIdentifier]) |  `
    Where-Object {                                          `
             $_.AccessControlType -eq 'Deny'                `
        -and $_.IdentityReference -eq $Administrators.Value `
    } |                                                     `
    ForEach-Object { $null = $RegAcl.RemoveAccessRule($_) }

# Create a new rule allowing the Administrators Full Control.
$RegRule = [System.Security.AccessControl.RegistryAccessRule]::new( `
             $Administrators                                        `
           , 'FullControl'                                          `
           , 'ContainerInherit'                                     `
           , 'None'                                                 `
           , 'Allow')
$RegACL.SetAccessRule($RegRule)
$RegKey.SetAccessControl($RegACL)

# Close the Registry Key.
$RegKey.Close()


##############################################################
# Step 4: Change the 'LocalizedString' property
# in the registry to suit your needs.
##############################################################
#
# With PowerShell 5, you need to use
# `Registry::HKEY_CLASSES_ROOT\..` syntax in order to be able
# to set the registry Type for the value
# with parameter '-Type'.
# As of PowerShell 7, the '-Type' parameter is included.

$RegPath = `
 'Registry::HKEY_CLASSES_ROOT\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}'
Set-ItemProperty -Path  $RegPath          `
                 -Name  'LocalizedString' `
                 -Value "%ComputerName%"  `
                 -Type  ExpandString      `
                 -Force

我在控制台中得到的文本如下:

PS C:\WINDOWS\system32> C:\Users\MihaiDobrescu\OneDrive\Documents\2_Facturi\12_-_Bank_Services\Digitization\Powershell\Change_Registry_Key.3.PS1 -RunAsAdministrator
VERBOSE: Enabling privilege 'SeTakeOwnershipPrivilege' for process powershell_ise

PS C:\WINDOWS\system32>

更新: 包含所有 Beautiful Soup 材料的最终版本。

再次感谢 @Theo,他已经调试了整个混乱过程。

注意: 令人惊讶的是,该片段甚至在虚拟机中也能正常工作,因为无需以管理员身份运行它,也不需要占有整个太阳系来解决这个问题。

# How to test:
#
# 1. Rename the My Computer Desktop Icon to "Fifi".
# 2. Remove the My Computer Desktop Icon from the Desktop View.
# 3. Run this snippet.
# 4. Observe how the My Computer Desktop Icon is produced on the Desktop View,
#    with the name "Tele-Ordinator" and with a very emotional Desktop Icon.

# Allow the execution of snippets.

Set-ExecutionPolicy               `
    -ExecutionPolicy RemoteSigned `
    -Scope           CurrentUser

# Produce the My Computer Desktop Icon on the Desktop View.

# HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel\
# {20D04FE0-3AEA-1069-A2D8-08002B30309D}
# 0 = show
# 1 = hide

$Path = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel"

$Name = "{20D04FE0-3AEA-1069-A2D8-08002B30309D}"

$Exist = "Get-ItemProperty -Path $Path -Name $Name"

if ($Exist)
{
    Set-ItemProperty     `
        -Path  $Path     `
        -Name  $Name     `
        -Value 0
}
Else
{
    New-ItemProperty     `
        -Path  $Path     `
        -Name  $Name     `
        -Value 0
}

# Rename the My Computer Desktop Icon from "This PC" to "Tele-Ordinator".

$My_Computer = 17

$Shell = New-Object -COMObject Shell.Application

$NSComputer = $Shell.Namespace($My_Computer)

$NSComputer.Self.Name = "Tele-Ordinator"

# Change the My Computer Desktop Icon.

$RegPath =                                                                                                                                    `
    'Registry::HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\DefaultIcon'

if (!(Test-Path -Path $RegPath))
{
    $null = New-Item             `
                -Path   $RegPath `
                -Force
}

Set-ItemProperty                                                               `
    -Path  $RegPath                                                            `
    -Name  '(Default)'                                                         `
    -Value 'Y:\Digitization\Icons\Robsonbillponte-Happy-Holidays-Pictures.ICO' `
    -Type  ExpandString                                                        `
    -Force

# Refresh the Desktop View.

$Definition = @'

    [System.Runtime.InteropServices.DllImport("Shell32.dll")]

    private static extern int SHChangeNotify(
          int    eventId
        , int    flags
        , IntPtr item1
        , IntPtr item2);

    public static void Refresh()
    {
        SHChangeNotify(
          0x8000000
        , 0x1000
        , IntPtr.Zero
        , IntPtr.Zero);
    }
'@

Add-Type                          `
    -MemberDefinition $Definition `
    -Namespace        WinAPI      `
    -Name             Explorer

[WinAPI.Explorer]::Refresh()

另一次最终更新用于设置和运行批处理文件,使用微软Windows批处理文件预处理系统自动化上述自动化过程:

这是一个名为Change_Desktop_Icons.BAT的简短代码片段。

ChDir %SystemRoot%\System32\WindowsPowerShell\v1.0\

%SystemRoot%\System32\WindowsPowerShell\v1.0\PowerShell.Exe Y:\Digitization\PowerShell\The_My_Computer_Desktop_Icon\Change_Desktop_Icon.PS1

Pause

这是事物的输出,在其桌面图标双击后出现。
'\\ISXPFV01.hd00.example.com\us_qv2_dem_user_data_pool_nra$\EE65037.HD00\Desktop'
CMD.EXE was started with the above path as the current directory.
UNC paths are not supported.  Defaulting to Windows directory.

C:\Windows>ChDir C:\WINDOWS\System32\WindowsPowerShell\v1.0\

C:\Windows\System32\WindowsPowerShell\v1.0>C:\WINDOWS\System32\WindowsPowerShell\v1.0\PowerShell.Exe Y:\Digitization\PowerShell\The_My_Computer_Desktop_Icon\Change_Desktop_Icon.PS1

C:\Windows\System32\WindowsPowerShell\v1.0>Pause
Press any key to continue . . .

1
您需要在注册表键HKEY_CLASSES_ROOT\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}中设置"LocalizedString"属性,例如"%UserName% on %ComputerName%"。但是,在此之前,您必须先拥有该键的所有权。另外请注意,该属性的类型为ExpandString(也称为REG_EXPAND_SZ)。 - Theo
你能否看一下我追加到问题正文的最新片段,并告诉我它是否与你在评论中所写的差不多?@Theo - DOBRESCU_Mihai.
1
我不确定你是否知道,但 HKEY_CLASSES_ROOT 不是一个真正的注册表根键。它实际上是一个映射键,包含其他根键信息的连接。你需要的是其他根键之一,HKEY_LOCAL_MACHINE\SOFTWARE\Classes。因此,用 HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D} 替换 HKEY_CLASSES_ROOT\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D},会更加有效。 - Compo
1
这应该有超过2个赞!这太棒了,干得好! - Bajan
1个回答

2

如前所述,更改“计算机”图标标题很麻烦。

以下代码适用于我在使用PowerShell 5.1的Windows 10 Pro中运行。

您需要以管理员身份运行此命令

#Requires -RunAsAdministrator

function Enable-Privilege {
    [CmdletBinding(ConfirmImpact = 'low', SupportsShouldProcess = $false)]  
    [OutputType('System.Boolean')]
    Param(
        [Parameter(Mandatory = $true, Position = 0)]
        [ValidateSet(
            "SeAssignPrimaryTokenPrivilege", "SeAuditPrivilege", "SeBackupPrivilege", "SeChangeNotifyPrivilege", 
            "SeCreateGlobalPrivilege", "SeCreatePagefilePrivilege", "SeCreatePermanentPrivilege", 
            "SeCreateSymbolicLinkPrivilege", "SeCreateTokenPrivilege", "SeDebugPrivilege", "SeEnableDelegationPrivilege", 
            "SeImpersonatePrivilege", "SeIncreaseBasePriorityPrivilege", "SeIncreaseQuotaPrivilege", 
            "SeIncreaseWorkingSetPrivilege", "SeLoadDriverPrivilege", "SeLockMemoryPrivilege", 
            "SeMachineAccountPrivilege", "SeManageVolumePrivilege", "SeProfileSingleProcessPrivilege", 
            "SeRelabelPrivilege", "SeRemoteShutdownPrivilege", "SeRestorePrivilege", "SeSecurityPrivilege", 
            "SeShutdownPrivilege", "SeSyncAgentPrivilege", "SeSystemEnvironmentPrivilege", "SeSystemProfilePrivilege", 
            "SeSystemtimePrivilege", "SeTakeOwnershipPrivilege", "SeTcbPrivilege", "SeTimeZonePrivilege", 
            "SeTrustedCredManAccessPrivilege", "SeUndockPrivilege", "SeUnsolicitedInputPrivilege")]
        [String]$Privilege,

        [Parameter(Position = 1)]
        $ProcessId = $PID,

        [switch]$Disable
        )


        Add-Type -TypeDefinition @'
using System;
using System.Runtime.InteropServices;

public class Privilege {
    [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
    internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);

    [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
    internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);

    [DllImport("advapi32.dll", SetLastError = true)]
    internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    internal struct TokPriv1Luid {
        public int Count;
        public long Luid;
        public int Attr;
    }

    internal const int SE_PRIVILEGE_ENABLED    = 0x00000002;
    internal const int SE_PRIVILEGE_DISABLED   = 0x00000000;
    internal const int TOKEN_QUERY             = 0x00000008;
    internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;

    public static bool EnablePrivilege(long processHandle, string privilege, bool disable) {
        bool retVal;
        TokPriv1Luid tp;
        IntPtr hproc = new IntPtr(processHandle);
        IntPtr htok = IntPtr.Zero;
        retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
        tp.Count = 1;
        tp.Luid = 0;
        if(disable) { tp.Attr = SE_PRIVILEGE_DISABLED; }
        else { tp.Attr = SE_PRIVILEGE_ENABLED; }
        retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
        retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
        return retVal;
    }
}
'@

    try {
        $proc   = Get-Process -Id $ProcessId -ErrorAction Stop
        $name   = $proc.ProcessName
        $handle = $proc.Handle
        $action = if ($Disable) { 'Disabling' } else { 'Enabling' }
        Write-Verbose ("{0} privilege '{1}' for process {2}" -f $action, $Privilege, $name)
        [Privilege]::EnablePrivilege($handle, $Privilege, [bool]$Disable)
    }
    catch {
        throw
    }
}

function Grant-FullControl ([string]$SubKey, [switch]$BreakInheritance) {
    # helper function to grant registry FullControl for Administrators on a certain subkey

    # better not use the string "Administrators", because this might have a different name in other cultures
    # $RegACL.SetOwner([System.Security.Principal.NTAccount]"Administrators")
    # use the Well-Known SID instead
    $Administrators = [System.Security.Principal.SecurityIdentifier]::new('S-1-5-32-544')   # local Administrators group

    $RegKey = [Microsoft.Win32.Registry]::ClassesRoot.OpenSubKey($SubKey,
                                                                 [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,
                                                                 [System.Security.AccessControl.RegistryRights]::TakeOwnership)

    $RegACL = $RegKey.GetAccessControl()
    if ($BreakInheritance) {
        # break inheritance, but keep permissions
        $RegACL.SetAccessRuleProtection($true, $true)
    }

    $RegACL.SetOwner($Administrators)
    $RegKey.SetAccessControl($RegACL)

    # refresh the ACL
    $RegACL = $RegKey.GetAccessControl()

    # test if there is a Deny rule in the ACL for Administrators and if so remove that rule
    $RegACL.GetAccessRules($true, $true, [System.Security.Principal.SecurityIdentifier]) |
        Where-Object { $_.AccessControlType -eq 'Deny' -and $_.IdentityReference -eq $Administrators.Value } |
        ForEach-Object { $null = $RegAcl.RemoveAccessRule($_) }

    # ceate a new rule allowing the Administrators FullControl
    $RegRule =[System.Security.AccessControl.RegistryAccessRule]::new($Administrators,
                                                                      'FullControl',
                                                                      'ContainerInherit',  # ContainerInherit, ObjectInherit
                                                                      'None',              # InheritOnly 
                                                                      'Allow')
    $RegACL.SetAccessRule($RegRule)
    $RegKey.SetAccessControl($RegACL)

    # close the registry key
    $RegKey.Close()
}

##################################################################################
# Step 1: give the current process the SeTakeOwnershipPrivilege
##################################################################################

$null = Enable-Privilege -Privilege SeTakeOwnershipPrivilege -Verbose

##################################################################################
# Step 2: change Key Owner to the local Administrators group and grant FullControl
##################################################################################

# first give Administrators full control on key "CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}"
Grant-FullControl -SubKey "CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}" -BreakInheritance

##################################################################################
# Step 3: change the 'LocalizedString' property in the registry to suit your needs
##################################################################################

# with PowerShell 5 you need to use `Registry::HKEY_CLASSES_ROOT\..` syntax in order to be able
# to set the registry Type for the value with parameter '-Type'.
# As of PowerShell 7 the '-Type' parameter is included

$regPath = 'Registry::HKEY_CLASSES_ROOT\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}'
Set-ItemProperty -Path $regPath -Name 'LocalizedString' -Value "%ComputerName%" -Type ExpandString -Force

##################################################################################
# Step 4: OPTIONAL. Change the Computer icon for NEW user logins
##################################################################################

# give  Administrators full control on subkey "CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\DefaultIcon"
# now, we do not need to break the inheritance as we needed for the root key
Grant-FullControl -SubKey "CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\DefaultIcon"

$regPath = 'Registry::HKEY_CLASSES_ROOT\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\DefaultIcon'
Set-ItemProperty -Path $regPath -Name '(Default)' -Value '%SystemRoot%\System32\imageres.dll,-149' -Type ExpandString -Force

##################################################################################
# Step 5: Change the Computer icon for the CURRENT user
##################################################################################

$regPath = 'Registry::HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\DefaultIcon'
Set-ItemProperty -Path $regPath -Name '(Default)' -Value '%SystemRoot%\System32\imageres.dll,-149' -Type ExpandString -Force

完成所有操作后,桌面上仍未显示计算机名称。您需要在桌面上按F5或使用找到的代码刷新桌面。


要更改图标本身,您需要更改registrypath中的默认值。

HKEY_CLASSES_ROOT\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\DefaultIcon 

对于未来的新登录或注册路径

HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\DefaultIcon

对于当前用户,默认情况下,它指向%SystemRoot%\System32\imageres.dll,-109,这意味着它从imageres.dll提取图标号109。在该dll中,有约343个图标,因此您可以选择使用同一资源中的另一个图标,或者从另一个现有的dll文件中获取一个图标(例如,您可以使用nirsoft的IconsExtract)。

我还没有测试过这个,但也应该可以将其指向您自己的图标的完整路径和文件名,例如%SystemDrive%\MyComputerIcon.ico

例如,这将更新图标以使用imageres.dll图标号149。

$regPath = 'Registry::HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\CLSID\{20D04FE0-3AEA-1069-A2D8-08002B30309D}\DefaultIcon'
Set-ItemProperty -Path $regPath -Name '(Default)' -Value '%SystemRoot%\System32\imageres.dll,-149' -Type ExpandString -Force

看起来像这样

在此输入图片描述


1
对于那个初始错误,我道歉@Theo。我并不是在寻找重命名桌面图标的方法。可能是因为我一开始找到了可以实现这一点的代码片段并且一直放在我脑海中,所以最初会问到重命名部分。但我并没有打算改变问题。那是我的最初问题,只是表述方式有误。即使是重命名部分的答案,我也很高兴能看到它能够正常工作,而目前在我的机器上并不能正常运行。我需要更加仔细地调试。当然,我将接受你的答案并给予赞扬。再次感谢! - DOBRESCU_Mihai.
1
@MihaiDobrescu 我已经再次编辑了。现在它将为当前用户以及未来的新用户更改图标。 - Theo
1
@MihaiDobrescu 需要添加提供程序“Registry::”。只有在使用它时,PS 5才支持Set-ItemProperty上的“Type”参数。现在已添加。 - Theo
1
在这种情况下,您需要使用 if (!(Test-Path -Path $regPath)) { $null = New-Item -Path $regPath -Force } 首先创建该键,并使用 Set-ItemProperty 命令在其中设置 (Default) - Theo
1
@MihaiDobrescu,确实是个难题。您最新的添加看起来很好,尽管我建议使用计算机自己磁盘上的自制图标(我假设Y:是映射驱动器),以防网络或映射出现故障。我想这样Windows加载会更快。总之,好问题! - Theo
显示剩余17条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接