Tsql Powershell:我需要帮助来修改冗长的SQL脚本文件

Tsql Powershell:我需要帮助来修改冗长的SQL脚本文件,tsql,powershell-4.0,Tsql,Powershell 4.0,我有一个很长的SQL脚本,其中包含许多/多个类似的部分(以及其他脚本部分): 我需要分析此脚本平铺,并仅修改脚本的行(如果不存在的话)…创建用户…行,以便“@@Placeholder@”被紧接创建用户字符串之后的同一行中方括号[]内的文本替换 因此,上述代码段中的行将变成: IF NOT EXISTS (SELECT name FROM sys.database_principals WHERE name = 'MyDomain\adcsuser')

我有一个很长的SQL脚本,其中包含许多/多个类似的部分(以及其他脚本部分):

我需要分析此脚本平铺,并仅修改脚本的
行(如果不存在的话)…创建用户…
行,以便“@@Placeholder@”被紧接
创建用户
字符串之后的同一行中方括号[]内的文本替换

因此,上述代码段中的行将变成:

IF NOT EXISTS (SELECT name FROM sys.database_principals 
               WHERE name = 'MyDomain\adcsuser')  
    CREATE USER [MyDomain\adcsuser] 
    FOR LOGIN [MyDomain\adcsuser] 
    WITH DEFAULT_SCHEMA = [MyDomain\adcsuser]
该文件有数百行,其中至少有十几个部分

记事本++查找替换,宏无法处理它,因为[]s之间的名称中有“\”,我无法找到如何使NP++在[]s之间复制文本

此外,我还试着复习了其他相关的答案,如:,但到目前为止仍然没有找到答案

由于脚本文件结构的复杂性,我对“读取整个文件并只使用正则表达式查找/替换”的方法持谨慎态度,因此我正在寻找一种更。。。RBAR(一行接一行)方法

动态SQL或参数化方法以及类似的建议不适合这种情况,因为脚本已经从现有的生产系统动态生成(并且我没有作为输出生成此脚本的实用程序的源代码)。我真的不能做出那样大规模的结构性改变


另外,在再次阅读这篇文章之后,我应该指出整个“IF note EXISTS…WITH DEFAULT_SCHEMA[*]”命令位于脚本文件的一行上(如果不够清晰)。

对于NotePad++来说,查找和替换支持正则表达式

如何查找包含“创建用户[someusername]”的所有行并将其替换为替换项@占位符@的示例如下:

.*是通配符,括号是正则表达式中的特殊字符,因此要将它们作为搜索的一部分,必须对它们进行转义。所以\[.\]会找到括号中的任何内容。我刚刚添加了createuser作为查找所有这些特定行的示例

确保在搜索模式下选择“正则表达式”

PowerShell,所有内容都在一行中,您可以阅读每一行,找到匹配项,提取用户,然后替换;将该行复制回新文件

输入测试文件:

PowerShell脚本示例:

#create new output file
new-item "C:\temp\test2.txt" -Force
foreach ($line in (get-content "C:\temp\test.txt"))
{
    #Find the the user between the brackets and remove the brackets.
    $user = ([regex]"\[.*\]").Match($line).value.replace("[","").replace("]","")
    #Replace PlaceHolder with user pulled from the brackets and write to new file
    $line -replace '@@PlaceHolder@@', $user | out-file "C:\temp\test2.txt" -Append  
}
然后输出文件的内容:

@Tim Mylott

整个问题都是由Powershell的DBATools的Export-DbaLogin命令在我的生产系统中生成的脚本引起的

该工具的输出脚本类似于您的第一个text.txt文件,因为它发出盲创建用户命令,而不首先测试用户是否已经存在

这不足以满足我们的需要(我们的生产数据库和系统已经存在多年了,现在到处都是旧的、坏的“lint”),所以我将脚本输出转换为Notepad++并添加了IF-EXIST。。。测试逻辑(有关详细信息,请参阅原始问题中的脚本)作为脚本中带有全局搜索和替换的CREATE USER命令的前缀。只是,我必须在测试的SELECT的WHERE子句中为用户名添加@Placeholder@

这给我留下了一个脚本,我必须用脚本文件中同一行的现有“创建用户”文本中的实际用户名字符串替换@@Placeholder@@文本

在NP++中,您引导我找到的解决方案是在NP++搜索中使用正则表达式来选择同一行中的用户ID字符串。从那时起,使用NP++宏录制来自动搜索和替换就相当简单和直接了


首先,我在网上找到了一个正则表达式,用于选择第一对匹配的[]s之间的文本,即:(?替换似乎不是一个好主意。将脚本参数化将是一个更好的主意。否则,您只是在注入时向世界开放。脚本是从正在升级到新服务器的现有SQL Server生成的。这里没有实际的SQL注入风险,因为此输入不来自“外部”。不幸的是,我没有生成脚本的工具的源代码,因此我无法在生成阶段解决此问题。如果您只想因此替换值,您看了吗?不充分。您缺少此处的关键思想。从逻辑上讲,我需要:1)找到脚本中需要更改的行;2)在检索行中查找用户名;3) 用发现的用户ID字符串替换@占位符@;4) 将更新的行与所有其他(跳过的)脚本行一起保存回文件(或新文件);5) 打肥皂,冲洗,根据需要重复。你不能那样做;没有动态SQL是不行的。如果是这样的话,你最好改变你的解决方案并将其参数化。蒂姆,你确实解决了我的问题,但你的答案是反的。@MarkBurns噢,该死,你是对的。我又看了一遍这篇文章,我完全偏离了你真正想要实现的目标。我更新了答案,以便在powershell中为您提供一个更好的示例,说明如何解决此问题。
#create new output file
new-item "C:\temp\test2.txt" -Force
foreach ($line in (get-content "C:\temp\test.txt"))
{
    #Find the the user between the brackets and remove the brackets.
    $user = ([regex]"\[.*\]").Match($line).value.replace("[","").replace("]","")
    #Replace PlaceHolder with user pulled from the brackets and write to new file
    $line -replace '@@PlaceHolder@@', $user | out-file "C:\temp\test2.txt" -Append  
}
-- FROM THIS:
IF NOT EXISTS (SELECT ... WHERE name = '@@PlaceHolder@@')  CREATE USER [MyDomain\AUser2]...
IF NOT EXISTS (SELECT ... WHERE name = '@@PlaceHolder@@')  CREATE USER [MyDomain\AUser3]...
IF NOT EXISTS (SELECT ... WHERE name = '@@PlaceHolder@@')  CREATE USER [MyDomain\AUser5]...
IF NOT EXISTS (SELECT ... WHERE name = '@@PlaceHolder@@')  CREATE USER [MyDomain\AUser1]...
IF NOT EXISTS (SELECT ... WHERE name = '@@PlaceHolder@@')  CREATE USER [MyDomain\AUser7]...
IF NOT EXISTS (SELECT ... WHERE name = '@@PlaceHolder@@')  CREATE USER [MyDomain\AUser8]...
IF NOT EXISTS (SELECT ... WHERE name = '@@PlaceHolder@@')  CREATE USER [MyDomain\AUserA]...
IF NOT EXISTS (SELECT ... WHERE name = '@@PlaceHolder@@')  CREATE USER [MyDomain\AUserB]...
IF NOT EXISTS (SELECT ... WHERE name = '@@PlaceHolder@@')  CREATE USER [MyDomain\AUserC]...


-- TO THIS:
IF NOT EXISTS (SELECT ... WHERE name = 'MyDomain\AUser2')  CREATE USER [MyDomain\AUser2]...
IF NOT EXISTS (SELECT ... WHERE name = 'MyDomain\AUser3')  CREATE USER [MyDomain\AUser3]...
IF NOT EXISTS (SELECT ... WHERE name = 'MyDomain\AUser5')  CREATE USER [MyDomain\AUser5]...
IF NOT EXISTS (SELECT ... WHERE name = 'MyDomain\AUser1')  CREATE USER [MyDomain\AUser1]...
IF NOT EXISTS (SELECT ... WHERE name = 'MyDomain\AUser7')  CREATE USER [MyDomain\AUser7]...
IF NOT EXISTS (SELECT ... WHERE name = 'MyDomain\AUser8')  CREATE USER [MyDomain\AUser8]...
IF NOT EXISTS (SELECT ... WHERE name = 'MyDomain\AUserA')  CREATE USER [MyDomain\AUserA]...
IF NOT EXISTS (SELECT ... WHERE name = 'MyDomain\AUserB')  CREATE USER [MyDomain\AUserB]...
IF NOT EXISTS (SELECT ... WHERE name = 'MyDomain\AUserC')  CREATE USER [MyDomain\AUserC]…
    #create new output file
new-item "C:\temp\test2.sql" -Force
foreach ($line in (get-content "C:\temp\test.sql"))
{
    if ($line.Contains("@@Placeholder@@"))
    {
    #Find the the user between the brackets and remove the brackets.
    $user = ([regex]"\[.+?\]").Match($line).value.replace("[","").replace("]","")
    #Replace PlaceHolder with user pulled from the brackets and write to new file
    $line -replace '@@Placeholder@@', $user | out-file "C:\temp\test2.sql" -Append 
    }
    else
    {
        out-file  "C:\temp\test2.sql" -Append -InputObject $line
    }

}