我对 SQL Server 很陌生。我有一个脚本可以在所有数据库中找到孤立用户并生成脚本以删除或映射用户以正确登录(如果可用)。
由于我想在大量服务器上运行脚本,我想到了使用 PowerShell 来帮助我。但我现在有两个问题:
- 脚本错误
- Power-shell 执行错误
问题 1:以下脚本本身返回输出,但仍然显示一些错误。我试图调试,但我无法这样做。
DECLARE @orphan_users TABLE (
Server NVARCHAR(MAX),
DBName sysname,
[user_name] sysname,
type_desc nvarchar(60),
default_schema_name sysname NULL,
create_date datetime,
modify_date DATETIME,
[sid] VARBINARY(85),
cr_type int
);
INSERT INTO @orphan_users (Server,
DBname,
[user_name],
type_desc,
default_schema_name,
create_date,
modify_date,
[sid],
cr_type
)
EXEC sp_msforeachdb
'use [?]
SELECT
@@SERVERNAME
,DB_NAME() DBname
,name
,type_desc
,default_schema_name
,create_date
,modify_date
,[sid]
,Datalength(sid) AA
from sys.database_principals
where type in (''S'')
and [sid] not in ( select [sid] from sys.server_principals where type in (''G'',''S'',''U'') )
and name not in (''dbo'',''guest'',''INFORMATION_SCHEMA'',''sys'' ,''MS_DataCollectorInternalUser'')';
DECLARE @db_users TABLE (
[LogInAtServerLevel] NVARCHAR(MAX),
[UserAtDBLevel] NVARCHAR(MAX),
DBname sysname
);
INSERT INTO @db_users ([LogInAtServerLevel], [UserAtDBLevel],DBname)
EXEC sp_msforeachdb
'use [?]
SELECT
susers.[name],
users.[name],
DB_NAME() DBname
from sys.database_principals users
inner join sys.database_role_members link
on link.member_principal_id = users.principal_id
inner join sys.database_principals roles
on roles.principal_id = link.role_principal_id
inner join sys.server_principals susers
on susers.sid = users.sid';
SELECT
a.Server,
a.DBName,
a.user_name,
b.name,cr_type,
c.UserAtDBLevel,
CASE
WHEN (b.name IS NULL) and (cr_type > 17)
THEN 'USE ' + QUOTENAME(a.DBname) + '; DROP USER ' + QUOTENAME(a.user_name) + ';'
WHEN (b.name IS not NULL) and (cr_type < 17) and (c.UserAtDBLevel is null)
THEN 'USE ' + QUOTENAME(a.DBname) + '; ALTER USER ' + QUOTENAME(a.user_name) + ' WITH LOGIN = ' + QUOTENAME(b.name)+';'
WHEN (b.name IS not NULL) and (cr_type < 17) and (c.UserAtDBLevel is not null)
THEN 'USE ' + QUOTENAME(a.DBname) + '; DROP USER ' + QUOTENAME(a.user_name) + ';'
WHEN (b.name IS NULL)
THEN 'USE ' + QUOTENAME(a.DBname) + '; DROP USER ' + QUOTENAME(a.user_name) + ';'
WHEN (b.name IS not NULL) and (cr_type > 17)
THEN 'USE ' + QUOTENAME(a.DBname) + '; DROP USER ' + QUOTENAME(a.user_name) + ';'
END as [remediation]
FROM ((@orphan_users a
left join sys.server_principals b on a.user_name = b.name)
left join @db_users c on c.DBname=a.DBName and c.LogInAtServerLevel=b.name)
ORDER BY a.user_name;
结果是
但是由于该错误,实例中的所有数据库都会出现类似的错误
“tempdbfrom”附近的语法不正确。消息 102,级别 15,状态 1,第 3 行
“modelfrom”附近的语法不正确。消息 102,级别 15,状态 1,第 3 行
“msdbfrom”附近的语法不正确。消息 102,级别 15,状态 1,第 3 行
'dbamonfrom' 附近的语法不正确。消息 102,第 15 级,状态 1,第 3 行
问题 2:由于脚本是准确的(至少在我的环境中),所以我尝试使用 power-shell 运行它,如下所示。它只返回错误,没有输出
Invoke-SqlCmd `
-InputFile "D:\temp\up.sql" `
-ServerInstance 'abc\sql2012' `
-IncludeSqlUserErrors
我已经尝试了使用 > 重定向输出的所有方法来启动和停止转录。他们似乎都没有捕捉到查询给出的结果,但是错误被准确捕捉到了..
如果任何一个问题得到解决,这对我来说将是一个很大的帮助。
该
dbatools
模块已经为您解决了这个问题。Get-DbaDbOrphanUser
- 报告一个或多个数据库中没有相应登录的所有用户Repair-DbaDbOrphanUser
- 查找孤儿用户,如果有同名登录,它将重新映射他们。Remove-DbaDbOrphanUser
- 定位孤立用户并将其从数据库中删除(您也可以这样做Repair-DbaDbOrphanUser -RemoveNotExisting
)。可能你的编辑有问题,或者我不知道到底是什么问题。但是我清除了所有空白
msforeachdb
并运行它,因此错误消失了。您是否考虑过 SQL Server 接受使用没有登录的用户,虽然它看起来像一个孤立的用户,但它可以被设计成这样?
创建用户文档说:
因此,在自动化该任务时要小心,因为如果您不熟悉正在使用的数据库,您可能会破坏某些东西。