The*_*war 5 sql-server powershell sql-server-2012 xp-cmdshell
我正在尝试从一堆服务器获取磁盘空间报告并将它们插入到 sql 表中..
下面是我正在尝试做的示例,服务器名称将从表中填充并作为逗号分隔列表传递。即使传递一台服务器也有相同的结果
set @ps = 'powershell.exe -noexit -c "
$computers=Get-WmiObject -Class Win32_Volume '+@servernames+'
foreach($computer in $computers)
{
$pscomputername=$computer.pscomputername
$name=$computer.name
$capacity=$computer.capacity
$freespace=$computer.freespace
$Label=$computer.Label
$insertquery="
INSERT INTO [dbo].[temp_disksdata]
(
[servername] ,
[DiskName] ,
[Capacity(GB)] ,
[FreeSpace(GB)],
[label]
)
VALUES
(''$pscomputername'' ,
''$name'' ,
''$capacity'',
''$freespace'',
''$Label''
)
GO
"
Invoke-SQLcmd -query $insertquery -ServerInstance ''someserver'' -Database dbname
}
"';
Run Code Online (Sandbox Code Playgroud)
现在我尝试将变量传递给 xp_cmdshell,如下所示
execute xp_cmdshell @ps;
Run Code Online (Sandbox Code Playgroud)
当在 SSMS 中调用时,上面返回 null,但在 powershell 中工作..
任何想法为什么?
以下是我尝试过的一些事情
1. shell 和 ssms 都使用相同的帐户(admin) 2.
尝试了多种方法,例如导入模块
3.XP_CMDshell 有效,但这仅针对此查询返回 null
4. 我尝试添加 -nowait,但这并没有也有帮助
我一直在尝试从一天多的时间完成这项工作,但这不起作用..我必须使用 xp_cmdshell,因为不允许编写 ac# 应用程序。bat 文件没有帮助,因为服务器名称作为逗号传递分开的名单。
我正在修改代码并被告知不要在被问到时重写
如果您需要更多信息,请告诉我
Repro:
下面是整个打印命令,如果你删除 powershell.exe 和 -c ,下面将在 powershell 中运行..
powershell.exe -c "
$computers=Get-WmiObject -Class Win32_Volume 'servername'
foreach($computer in $computers)
{
$pscomputername=$computer.pscomputername
$name=$computer.name
$capacity=$computer.capacity
$freespace=$computer.freespace
$Label=$computer.Label
$insertquery="
INSERT INTO [dbo].[temp_disksdata]
(
[servername] ,
[DiskName] ,
[Capacity(GB)] ,
[FreeSpace(GB)],
[label]
)
VALUES
('$pscomputername' ,
'$name' ,
'$capacity',
'$freespace',
'$Label'
)
"
Invoke-SQLcmd -query $insertquery -ServerInstance 'servername' -Database dbname
}
"
Run Code Online (Sandbox Code Playgroud)
这里有几个问题:
主要问题是 CMD shell 在每行通过 return 进入时执行;它不会等待诸如 的“命令结束”指示符;
,也不会尝试通过解析来找出它(就像 SQL 在提交批处理时所做的那样),因为无法知道 a 是否return结束了“命令”或不是。通常你可以使用^
用于行继续,但这似乎不适用于输入参数(至少不是带有未闭合引号的参数)。
因此,为此您需要将所有内容减少到一行。这很简单,因为您可以将回车符(字符 13)替换为空字符串,并将换行符/换行符(字符 10)替换为空格。但是,单独这样做是行不通的,因为 PowerShell 语句需要用换行符或分号分隔。目前正在使用换行符,但如果我们用空格替换它们,则将需要分号。
因此,第 1 步是在每个实际的 PowerShell 命令后附加一个分号。一般来说,这可能是一种很好的形式,与 T-SQL 相同。
第 2 步将对变量进行两次REPLACE
调用,@ps
以将其转换为单行脚本。
您已嵌入双引号,用于创建INSERT
语句。那些需要用反斜杠 ( \
)转义。
Get-WmiObject
当您尝试在此处使用它时,它似乎不起作用。我不得不添加-ComputerName
以传递系统的名称。如果我将其留空,则它返回本地系统信息,但如果您想返回远程服务器的信息,那么您可能需要使用-ComputerName
开关并一次传入一台服务器。这很可能需要一个额外的外部循环来处理多个服务器名称(并且您将在那里传入@ServerNames
以获取拆分以遍历列表)。
“容量”和“自由空间”真的作为字符串存储在数据库中吗?如果没有,您可能希望删除INSERT
语句中这些“值”周围的单引号。
以下至少执行。您可以从那里进行调试。我遇到了错误,没有找到“Invoke-SQLcmd”模块或其他东西。
DECLARE @ServerNames NVARCHAR(4000);
SET @ServerNames = N'ALBRIGHT';
DECLARE @ps NVARCHAR(4000);
SET @ps = N'powershell.exe -noexit -c "
$computers=Get-WmiObject -Class Win32_Volume -ComputerName ' + @ServerNames + N';
foreach($computer in $computers)
{
$pscomputername=$computer.pscomputername;
$name=$computer.name;
$capacity=$computer.capacity;
$freespace=$computer.freespace;
$Label=$computer.Label;
$insertquery=\";
INSERT INTO [dbo].[temp_disksdata]
(
[servername] ,
[DiskName] ,
[Capacity(GB)] ,
[FreeSpace(GB)],
[label]
)
VALUES
(''$pscomputername'' ,
''$name'' ,
''$capacity'',
''$freespace'',
''$Label''
)
GO
\";
Invoke-SQLcmd -query $insertquery -ServerInstance ''someserver'' -Database dbname;
}
"';
SET @ps = REPLACE(REPLACE(@ps, NCHAR(13), N''), NCHAR(10), N' ')
PRINT @ps;
EXEC xp_cmdshell @ps;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1887 次 |
最近记录: |