Powershell 修改用户配置文件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Powershell 修改用户配置文件相关的知识,希望对你有一定的参考价值。

最近公司打算统一修改AD用户的一些属性,包括SamAccountName,UPN,Office365的UPN,这样保证这些属性和邮件地址是一致的。这些修改本身不难,都可以通过PowerShell批量实现,问题在于修改之后有很多额外的问题,例如Outlook的ost文件啦,通过AD进行LDAP登录的工具了,一些软件的保存路径等需要处理。


修改了AD登录名之后的首要问题就是计算机上的用户配置文件需要进行同步修改。公司没用SCCM,因此只有自己想办法了。豆子做了些测试,基本上需要做以下操作:

  1. 以其他管理员身份登录计算机;

  2. 确认该用户abc已经退出登录状态,可以通过任务管理器或者quser来操作

  3. 修改C:\users\abc 的文件名为新的用户名C:\users\abc1

  4. 修改注册表,这个里面有一堆根据SID命名的key,需要找到对应的,然后修改对应的profileImagePath

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList

    技术分享

  5. 创建新的symboLink连接从 c:\users\abc  <==> c:\users\abc1。windows下面有自带的mklink命令可以使用,比如 mklink /D c:\users \abc c:\users\abc1。PS5以后可以用New-item创建,但是早期的版本没有原生的PS命令,只能间接调用cmd,或者自己写一个方法



上面的操作都可以通过PS脚本来实现。

#创建SymLink的方法,这个网上发现有现成的,我就直接下载了
function New-Symlink {
    <#
    .SYNOPSIS
        Creates a symbolic link.
    #>
    param (
        [Parameter(Position=0, Mandatory=$true)]
        [string] $Link,
        [Parameter(Position=1, Mandatory=$true)]
        [string] $Target
    )
    Invoke-MKLINK -Link $Link -Target $Target -Symlink
}
function New-Hardlink {
    <#
    .SYNOPSIS
        Creates a hard link.
    #>
    param (
        [Parameter(Position=0, Mandatory=$true)]
        [string] $Link,
        [Parameter(Position=1, Mandatory=$true)]
        [string] $Target
    )
    Invoke-MKLINK -Link $Link -Target $Target -HardLink
}
function New-Junction {
    <#
    .SYNOPSIS
        Creates a directory junction.
    #>
    param (
        [Parameter(Position=0, Mandatory=$true)]
        [string] $Link,
        [Parameter(Position=1, Mandatory=$true)]
        [string] $Target
    )
    Invoke-MKLINK -Link $Link -Target $Target -Junction
}
function Invoke-MKLINK {
    <#
    .SYNOPSIS
        Creates a symbolic link, hard link, or directory junction.
    #>
    [CmdletBinding(DefaultParameterSetName = "Symlink")]
    param (
        [Parameter(Position=0, Mandatory=$true)]
        [string] $Link,
        [Parameter(Position=1, Mandatory=$true)]
        [string] $Target,
        [Parameter(ParameterSetName = "Symlink")]
        [switch] $Symlink = $true,
        [Parameter(ParameterSetName = "HardLink")]
        [switch] $HardLink,
        [Parameter(ParameterSetName = "Junction")]
        [switch] $Junction
    )
    # Ensure target exists.
    if (-not(Test-Path $Target)) {
        throw "Target does not exist.`nTarget: $Target"
    }
    # Ensure link does not exist.
    if (Test-Path $Link) {
        throw "A file or directory already exists at the link path.`nLink: $Link"
    }
    $isDirectory = (Get-Item $Target).PSIsContainer
    $mklinkArg = ""
    if ($Symlink -and $isDirectory) {
        $mkLinkArg = "/D"
    }
    if ($Junction) {
        # Ensure we are linking a directory. (Junctions don‘t work for files.)
        if (-not($isDirectory)) {
            throw "The target is a file. Junctions cannot be created for files.`nTarget: $Target"
        }
        $mklinkArg = "/J"
    }
    if ($HardLink) {
        # Ensure we are linking a file. (Hard links don‘t work for directories.)
        if ($isDirectory) {
            throw "The target is a directory. Hard links cannot be created for directories.`nTarget: $Target"
        }
        $mkLinkArg = "/H"
    }
    # Capture the MKLINK output so we can return it properly.
    # Includes a redirect of STDERR to STDOUT so we can capture it as well.
    $output = cmd /c mklink $mkLinkArg `"$Link`" `"$Target`" 2>&1
    if ($lastExitCode -ne 0) {
        throw "MKLINK failed. Exit code: $lastExitCode`n$output"
    }
    else {
        Write-Output $output
    }
}
 
 
 
#定义一个Flag跳出循环
$flag=$true
while($flag){
    $oldName=read-host "Please input the old user name"
    write-host ‘Searching user profile..‘ -ForegroundColor Cyan
     
    #测试该用户是否已经登录,这里有个小技巧把quser的字符串结果转换为对象,具体解释参考博客
    http://beanxyz.blog.51cto.com/5570417/1906162
    if (Test-Path "c:\users\$oldName"){
        write-host "User Profile c:\users\$oldName found." -ForegroundColor Cyan
        #Check if the user is currently logged In
        $quser = (quser) -replace ‘\s{2,17}‘, ‘,‘ | ConvertFrom-Csv
        $sessionId = $quser | Where-Object { $_.Username -eq $newName } | select -ExpandProperty id
         
        #如果已经登录,那么强行退出这个用户
        foreach($id in $sessionId){
            if($id -ne $null){
                write-host "Detected User $newName still login" -ForegroundColor red
                Write-Host "Force logoff the user" -ForegroundColor red
                logoff $id
            }
         
        }
        
        $newName=read-host "Please input the new name"
        $oldpath="c:\users\$oldName"
        $newpath="c:\users\$newName"
         
        #重命名文件夹
        rename-item $oldpath $newpath -Confirm -ErrorAction Stop
        write-host "Searching Registry Information " -ForegroundColor Cyan
         
        #查询对应的注册表Key
        Get-ChildItem "hklm:\software\microsoft\windows nt\currentversion\profilelist" | foreach{
            #Get the username from SID
            $sid=$_.Name.Split(‘\‘)[-1];
             
            #根据SID来匹配用户,如果用户匹配成功,那么修改对应的ProfileList
            try{
            $objSID = New-Object System.Security.Principal.SecurityIdentifier ($sid)
            $objUser = $objSID.Translate( [System.Security.Principal.NTAccount]) 
            $username=$objUser.Value
            }
            catch{}
            #change registry keys
            if(($username -eq "omnicom\$oldName") -or ($username -eq "omnicom\$newName")){
                write-host "Found Registry Information of user profile $newName" -ForegroundColor Cyan
                $keys=Get-ItemProperty "hklm:\software\microsoft\windows nt\currentversion\profilelist\$sid" 
                $keys.ProfileImagePath=$newpath
                write-host "Registry key profile list is changed to $newpath" -ForegroundColor Cyan
                 
                 
                #调用上面的方法,创建Symbolink
                #Create new symbolink
                #New-Item -Path $oldpath -ItemType Junction -Value $newpath
                New-Symlink -Link $oldpath -Target $newpath
                 
                break;
            }
            else{
                write-host "$username Name not match...skip" -ForegroundColor Yellow
             
            }
         
        }
        $flag=$false
         
    }
    else {
        write-host "Profile is not found. Please try again" -ForegroundColor red
    }
}


执行效果,我直接把这个文件扔到一个远程电脑的C盘下测试,然后以本地管理员身份登录,执行这个脚本,成功!



技术分享

技术分享

本文出自 “麻婆豆腐” 博客,请务必保留此出处http://beanxyz.blog.51cto.com/5570417/1930788

以上是关于Powershell 修改用户配置文件的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段11——vue路由的配置

VSCode自定义代码片段11——vue路由的配置

VSCode自定义代码片段11——vue路由的配置

powershell PS SP用户配置文件获取用户

在 PowerShell 中查找最新修改的文​​件信息

如何通过powershell将用户权限分配给本地用户帐户?