【问题标题】:Splitting output of a string into separate strings将字符串的输出拆分为单独的字符串
【发布时间】:2017-09-19 18:40:18
【问题描述】:

我一直在编写一个 powershell 脚本,这真的让我大吃一惊。脚本分为两部分。

  1. 第一部分是获取域中所有服务器的函数。我们有 4 个不同的域,所以我分别检查每个域并输出结果。

  2. 第二部分是在特定远程机器上输出软件的功能。在我的例子中,上面函数的输出将被植入到这个函数中,以查看服务器是否安装了特定的软件。

软件搜索功能正常。我得到所有服务器输出的功能是我遇到的问题。

问题是,当我输出服务器列表(输出正确)时,它会将所有内容输出到一个大的多行字符串中......

例如,假设我有 5 台服务器:(ServerA、ServerB、ServerC、ServerD、ServerE)。

当我运行代码时,我会得到每个域的所有服务器的输出,如下所示:

TestA.com

ServerA
ServerB
ServerC
ServerD
ServerE

TestB.com

ServerA
ServerB
ServerC
ServerD
ServerE

TestC.com

ServerA
ServerB
ServerC
ServerD
ServerE

TestD.com

ServerA
ServerB
ServerC
ServerD
ServerE

但是每个域输出都是 1 个字符串,因此我无法将其播种到检查软件的函数中,因为它试图在“ServerA、ServerB、ServerC、ServerD、ServerE”中找到它,而不是单独在每个服务器中找到它。

我希望这是有道理的。这是我获取服务器列表的代码。

#Clear Screen
CLS

function Get-Servers
{
    #Variables
    [array]$MyDomains="TestA.com","TestB.com","TestC.com","TestD.com"
    [array]$MySearchBase="dc=TestA,dc=com","dc=TestB,dc=com","dc=TestC,dc=com","dc=TestD,dc=com"


    for($i=0; $i -lt $MyDomains.Count; $i++)
    {
        Write-Output $($MyDomains[$i])

        $MyServers = Get-ADComputer -Filter 'OperatingSystem -like "Windows*Server*"' -Properties Name -SearchBase $($MySearchBase[$i]) -Server $($MyDomains[$i]) | Format-Table Name -HideTableHeaders | out-string

        foreach ($MyServer in $MyServers)
        {
            $MyServer
            pause
        }   
    }
}

#Get list of servers
Get-Servers

如何将每个服务器的输出分别存储在“$MyServer”变量中?

编辑: 这是我查找远程软件的功能

function Get-RemoteRegistryProgram
{
  <#
    .Synopsis
      Uses remote registry to read installed programs
    .DESCRIPTION
      Use dot net and the registry key class to query installed programs from a 
      remote machine
    .EXAMPLE
      Get-RemoteRegistryProgram -ComputerName Server1
  #>
    [CmdletBinding()]
    Param
    (
        [Parameter(
            ValueFromPipeline=$true,
            ValueFromPipelineByPropertyName=$true, 
            Position=0)]
        [string[]]
        $ComputerName = $env:COMPUTERNAME
    )
    begin
    {
        $hives = @(
            [Microsoft.Win32.RegistryHive]::LocalMachine,
            [Microsoft.Win32.RegistryHive]::CurrentUser
        )

        $nodes = @(
            "Software\Microsoft\Windows\CurrentVersion\Uninstall",
            "Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
        )
    }
    process
    {
        $ComputerName

        forEach ($computer in $ComputerName)
        {
            forEach($hive in $hives)
            {
                try
                {
                    $registry = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($hive,$computer)
                }
                catch
                {
                    throw $PsItem
                }
                forEach($node in $nodes)
                {
                    try 
                    {
                        $keys = $registry.OpenSubKey($node).GetSubKeyNames()

                        forEach($key in $keys)
                        {
                            $displayname = $registry.OpenSubKey($node).OpenSubKey($key).GetValue('DisplayName')

                            if($displayname)
                            {
                                $installedProgram = @{
                                   # ComputerName = $computer
                                    DisplayName = $displayname
                                   # Version = $registry.OpenSubKey($node).OpenSubKey($key).GetValue('DisplayVersion')
                                }
                                New-Object -TypeName PSObject -Property $installedProgram
                            }
                        }
                    }
                    catch
                    {
                        $orginalError = $PsItem
                        Switch($orginalError.FullyQualifiedErrorId)
                        {
                            'InvokeMethodOnNull' 
                            {
                                #key maynot exists
                            }
                            default 
                            {
                                throw $orginalError 
                            }
                        }
                    } 
                }
            }
        }
    }
    end
    {

    }
}

编辑 2:

如果我像这样修改我的服务器功能:

for($i=0; $i -lt $MyDomains.Count; $i++)
{
    Write-Output $($MyDomains[$i])

    $MyServers = Get-ADComputer -Filter 'OperatingSystem -like "Windows*Server*"' -Properties Name -SearchBase $($MySearchBase[$i]) -Server $($MyDomains[$i]) | Format-Table Name -HideTableHeaders

    foreach ($MyServer in $MyServers)
    {
        Get-RemoteRegistryProgram -ComputerName $MyServer
    }   

}

我收到以下错误:

Microsoft.PowerShell.Commands.Internal.Format.FormatStartData
Exception calling "OpenRemoteBaseKey" with "2" argument(s): "The network path was not found.
"
At line:47 char:21
+                     $registry = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey ...
+                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : IOException

提前感谢您的帮助!

【问题讨论】:

  • 无需重新发明轮子。如果你想在远程计算机上安装软件,你可以使用我不久前写的脚本:Auditing 32-Bit and 64-Bit Applications with PowerShell
  • 谢谢。我并不是说听起来无知,但我正在尝试运行它并且遇到了一些麻烦。我有一个我尝试使用的 server.txt 文件。获取内容 u:\scripts\servers.txt | get-installedapp2 -Publisher "SysAid" 你的代码出错了。
  • 1) 您没有说出是什么错误(请记住,没有人可以看到您的屏幕)。 2)2 是从哪里来的Get-InstalledApp 的末尾?脚本名称末尾没有2
  • 这是你的函数: function get-installedapp2($computerName) { 在你的过程中我看到: if ($PIPELINEINPUT) { get-installedapp2 $_ } else { $ComputerName | foreach-object { get-installedapp2 $_ } }
  • 欢迎阅读这篇文章。它提供了示例。

标签: string powershell dns active-directory


【解决方案1】:

您的代码正在将服务器名称转换为字符串

$MyServers = Get-ADComputer -Filter 'OperatingSystem -like "Windows*Server*"' -Properties Name -SearchBase $($MySearchBase[$i]) -Server $($MyDomains[$i]) | Format-Table Name -HideTableHeaders | out-string

最后一部分是out-string。与其通过管道传递到格式表并将其作为字符串推出,不如保留对象并使用每个对象中的属性来获取每个服务器的名称。

【讨论】:

  • 感谢您的回复。但是,如果我删除了输出字符串,那么它可以工作,那么我无法将值输入我的软件功能。我收到一条错误消息“Microsoft.PowerShell.Commands.Internal.Format.FormatStartData 异常调用“OpenRemoteBaseKey”和“2”参数:“找不到网络路径。 " At line:47 char:21 + $registry = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey ... + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : IOException "
  • 我更新了我的原始帖子以包含软件功能。如果我按照您上面提到的方式进行了调整并像这样调用函数:Get-RemoteRegistryProgram -ComputerName $MyServer
【解决方案2】:

我最终重写了一些东西并解决了我的问题。为了避免字符串问题,我将结果导出到一个文本文件,然后使用 get-content 从文本文件中逐行读取并为每个服务器播种,让我知道哪些服务器有我需要的软件。这是最终结果。

#Clear Screen
CLS

function Get-RemoteRegistryProgram
{
  <#
    .Synopsis
      Uses remote registry to read installed programs
    .DESCRIPTION
      Use dot net and the registry key class to query installed programs from a 
      remote machine
    .EXAMPLE
      Get-RemoteRegistryProgram -ComputerName Server1
  #>
    [CmdletBinding()]
    Param
    (
        [Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=0)][string]$ComputerName = $env:COMPUTERNAME,
        [Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Position=1)][string]$SoftwareName
    )
    begin
    {
        $hives = @(
            [Microsoft.Win32.RegistryHive]::LocalMachine,
            [Microsoft.Win32.RegistryHive]::CurrentUser
        )

        $nodes = @(
            "Software\Microsoft\Windows\CurrentVersion\Uninstall",
            "Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
        )
    }
    process
    {
        $ComputerName
        $skip = $false

        forEach ($computer in $ComputerName)
        {
            forEach($hive in $hives)
            {
                try
                {
                    $registry = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($hive,$computer)
                }
                catch
                {
                    $skip = $true                
                }

                if($skip -eq $false)
                {
                    forEach($node in $nodes)
                    {
                        try 
                        {
                            $keys = $registry.OpenSubKey($node).GetSubKeyNames()

                            forEach($key in $keys)
                            {
                                $displayname = $registry.OpenSubKey($node).OpenSubKey($key).GetValue('DisplayName')

                                #Modified by James
                                if(($displayname) -like "*$SoftwareName*")
                                {
                                    $displayname + "`t" + $computer >> c:\scripts\sysaidServers.txt
                                }

                                <# Modified by James
                                if($displayname)
                                {
                                    $installedProgram = @{
                                       # ComputerName = $computer
                                        DisplayName = $displayname
                                       # Version = $registry.OpenSubKey($node).OpenSubKey($key).GetValue('DisplayVersion')
                                    }
                                    New-Object -TypeName PSObject -Property $installedProgram
                                }
                                #>
                            }
                        }
                        catch
                        {

                        <#
                            $orginalError = $PsItem
                            Switch($orginalError.FullyQualifiedErrorId)
                            {
                                'InvokeMethodOnNull' 
                                {
                                    #key maynot exists
                                }
                                default 
                                {
                                    throw $orginalError 
                                }
                            }
                        #>
                        } 
                    }
                }
            }
        }
    }
    end
    {

    }
}

#Output the servers to a txt file
function Get-Servers
{
    param ([Parameter( Mandatory=$true)][string]$SaveFile)

    #Variables
    [array]$MyDomains="DomainA.com","DomainB.com","DomainC.com","DomainD.com"
    [array]$MySearchBase="dc=DomainA,dc=com","dc=DomainB,dc=com","dc=DomainC,dc=com","dc=DomainD,dc=com"


    for($i=0; $i -lt $MyDomains.Count; $i++)
    {
        #I only want servers running Windows Server OS
        $MyServers = Get-ADComputer -Filter 'OperatingSystem -like "Windows*Server*"' -Properties Name -SearchBase $($MySearchBase[$i]) -Server $($MyDomains[$i]) | Format-Table Name -HideTableHeaders | out-string
        #Remove all whitespace and export to txt file
        $MyServers.Trim() -replace (' ', '') >> $SaveFile
    }
}

function CheckServerSoftware
{
    param ([Parameter( Mandatory=$true)][string]$SaveFile)

    Get-Content $SaveFile | ForEach-Object {
        if($_ -match $regex)
        {
            $computer = $_.ToString()
            Get-RemoteRegistryProgram -ComputerName $computer.Trim() $SoftwareName
            Write-Output ""
        }
    }
}

#Path to where our exported server list is
$SaveFile = "c:\scripts\servers.txt"
$SoftwareName = "SysAid"

#If the file already exists, remove it
Remove-Item $SaveFile

#Create the text file with servers
Get-Servers $SaveFile

#Import our server list and check software on each server
CheckServerSoftware $SaveFile

【讨论】:

    猜你喜欢
    • 2013-03-01
    • 1970-01-01
    • 2017-04-15
    • 2015-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多