最近公司打算统一修改AD用户的一些属性,包括SamAccountName,UPN,Office365的UPN,这样保证这些属性和邮件地址是一致的。这些修改本身不难,都可以通过PowerShell批量实现,问题在于修改之后有很多额外的问题,例如Outlook的ost文件啦,通过AD进行LDAP登录的工具了,一些软件的保存路径等需要处理。
修改了AD登录名之后的首要问题就是计算机上的用户配置文件需要进行同步修改。公司没用SCCM,因此只有自己想办法了。豆子做了些测试,基本上需要做以下操作:
以其他管理员身份登录计算机;
确认该用户abc已经退出登录状态,可以通过任务管理器或者quser来操作
修改C:\users\abc 的文件名为新的用户名C:\users\abc1
修改注册表,这个里面有一堆根据SID命名的key,需要找到对应的,然后修改对应的profileImagePath
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList
创建新的symboLink连接从 c:\users\abc <==> c:\users\abc1。windows下面有自带的mklink命令可以使用,比如 mklink /D c:\users \abc c:\users\abc1。PS5以后可以用New-item创建,但是早期的版本没有原生的PS命令,只能间接调用cmd,或者自己写一个方法
上面的操作都可以通过PS脚本来实现。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
|
#创建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盘下测试,然后以本地管理员身份登录,执行这个脚本,成功!
本文转自 beanxyz 51CTO博客,原文链接:http://blog.51cto.com/beanxyz/1930788,如需转载请自行联系原作者