none
Reutilizar objeto o clase 'custom' en ScriptBlock RRS feed

  • 问题

  • Hola,

    Tengo un script que recorre las máquinas de un dominio y ejecuta código en cada una de ellas.

    Quisiera utilizar el siguiente objeto dentro de un ScriptBlock, y que al final del ScriptBlock saque la información de la máquina en concreto en donde se está utilizando, la guarde en una variable, y posteriormente se muestren los datos ordenados de todas las máquinas : 

    $machine = [pscustomobject]@{
        IP = (Get-WmiObject -class win32_NetworkAdapterConfiguration -Filter 'ipenabled = "true"').ipaddress[0]
        ComputerName = [Environment]::GetEnvironmentVariable("ComputerName")
        Vulnerable = $false
        TypeGPU = Get-WmiObject win32_VideoController -Property AdapterCompatibility
        NameGPU = Get-WmiObject win32_VideoController -Property Caption
        GPUVersion = Get-WmiObject win32_VideoController -Property DriverVersion
        Description = ""
    }

    He intentado distintos métodos, como usar variables globales, o en vez de un objeto crear una clase, y no he sido capaz de que funcione. Estaría eternamente agradecido si me aportáis una solución, o una forma mejor o más eficiente de hacerlo. 

    Os adjunto el resto del código:
    $Output=@()
    
    $c = Get-ADComputer -Properties IPv4Address -Filter {Enabled -eq $true}
    $cred = Get-Credential
    
    echo ""
    if($cred){
        foreach ($cname in $c.name ) {
           
            if(test-connection -ComputerName $cname -Count 1 -Quiet){
                try{
                    $session = New-PSSession -ComputerName $cname -Credential $cred
                    Invoke-Command -Session $session -ScriptBlock{
                        
                        if($machine.TypeGPU.AdapterCompatibility -like '*NVIDIA*') 
                        {
                            $version = $machine.GPUVersion.DriverVersion.Substring($machine.GPUVersion.DriverVersion.Length - 6, 6)
    
                            if($machine.NameGPU.Caption -like '*Geforce*') {
                                if($version -lt 4.1917){$machine.Vulnerable = $true}
                            }
                            elseif(($machine.NameGPU.Caption -like '*Quadro*') -or ($machine.NameGPU.Caption -like '*NVS*')){
                                if($version -lt 4.1917){$machine.Vulnerable = $true}
                            }
                            elseif($gpu.Caption -like '*Tesla*'){
                                if($version -lt 4.1229){$machine.Vulnerable = $true}
                            }
                        }
                        else{ $machine + "The machine does not have NVIDIA GPU or does not contain NVIDIA drivers"}
    
                    }#ScriptBlock
                    
                    $Output += $machine | select IP,ComputerName,Vulnerable
                    Remove-PSSession -Session $session
    
                }catch{ Write-Host -ForegroundColor Red -BackgroundColor Yellow "$cname is active, but the check can not be performed. Verify that the Administrator credentials are correct, that the remote computer has WinRM actived, or that Firewall rules are not blocking the connection"}
            }
            else{ Write-Host -ForegroundColor DarkYellow "$cname does not respond to ping or the machine is off. Check that firewall rules are not blocking the connection"}
        }#foreach
    }
    else{ Write-Host -ForegroundColor Red -BackgroundColor Yellow "Administrator credentials are required to run the script`n"}
    
    $Output | Out-GridView -Wait -Title "List of vulnerable machines"

    Gracias ! 
    2019年3月17日 14:31

答案

  • Buenas,

    ¿Es necesario establecer una sesión remota abierta permanentemente?

    Podrías simplemente utilizar Invoke-Command, recoges los datos, generas tu variable en local y automáticamente se cierra la sesión remota.

    Por ejemplo:

    foreach ($ServerName in $Server)
    {
    
        $Machine = Invoke-Command -Credential $Cred -ComputerName $ServerName -ScriptBlock {
    
            [pscustomobject]@{
                IP = (Get-WmiObject -class win32_NetworkAdapterConfiguration -Filter 'ipenabled = "true"').ipaddress[0]
                ComputerName = $ServerName
                Vulnerable = $false
                TypeGPU = Get-WmiObject -class win32_VideoController -Property AdapterCompatibility
                NameGPU = Get-WmiObject -class win32_VideoController -Property Caption
                GPUVersion = Get-WmiObject -class win32_VideoController -Property DriverVersion
                Description = ""
            }
    
    
    
        }
    
        if(test-connection)
        {
            #Some Code
        }
    }


    • 已编辑 Jebisata 2019年3月21日 8:36
    • 已标记为答案 v3nt4n1t0 2019年3月31日 18:40
    2019年3月21日 8:35

全部回复

  • Buenos días,

    Prueba así:

    $Output=@()
    
    $c = Get-ADComputer -Properties IPv4Address -Filter {Enabled -eq $true}
    $cred = Get-Credential
    
    echo ""
    if($cred){
        foreach ($Cname in $c.name ) {
    
        $machine = [pscustomobject]@{
        IP = (Get-WmiObject -ComputerName $Cname -Credential $cred -class win32_NetworkAdapterConfiguration -Filter 'ipenabled = "true"').ipaddress[0]
        ComputerName = $Cname
        Vulnerable = $false
        TypeGPU = Get-WmiObject -ComputerName $Cname -Credential $cred -class win32_VideoController -Property AdapterCompatibility
        NameGPU = Get-WmiObject -ComputerName $Cname -Credential $cred -class win32_VideoController -Property Caption
        GPUVersion = Get-WmiObject -ComputerName $Cname -Credential $cred -class win32_VideoController -Property DriverVersion
        Description = ""
        }
           
            if(test-connection -ComputerName $Cname -Count 1 -Quiet){
                try{
                    
                        
                        if($machine.TypeGPU.AdapterCompatibility -like '*NVIDIA*') 
                        {
                            $version = $machine.GPUVersion.DriverVersion.Substring($machine.GPUVersion.DriverVersion.Length - 6, 6)
    
                            if($machine.NameGPU.Caption -like '*Geforce*') {
                                if($version -lt 4.1917){$machine.Vulnerable = $true}
                            }
                            elseif(($machine.NameGPU.Caption -like '*Quadro*') -or ($machine.NameGPU.Caption -like '*NVS*')){
                                if($version -lt 4.1917){$machine.Vulnerable = $true}
                            }
                            elseif($gpu.Caption -like '*Tesla*'){
                                if($version -lt 4.1229){$machine.Vulnerable = $true}
                            }
                        }
                        else{ "$cname does not have NVIDIA GPU or does not contain NVIDIA drivers"}
    
                    
                    
                    $Output += $machine | select IP,ComputerName,Vulnerable
                    
    
                }catch{ Write-Host -ForegroundColor Red -BackgroundColor Yellow "$cname is active, but the check can not be performed. Verify that the Administrator credentials are correct, that the remote computer has WinRM actived, or that Firewall rules are not blocking the connection"}
            }
            else{ Write-Host -ForegroundColor DarkYellow "$cname does not respond to ping or the machine is off. Check that firewall rules are not blocking the connection"}
        }#foreach
    }
    else{ Write-Host -ForegroundColor Red -BackgroundColor Yellow "Administrator credentials are required to run the script`n"}
    
    $Output | Out-GridView -Wait -Title "List of vulnerable machines"

    2019年3月19日 11:08
  • OH ! Muchas gracias ! Me has abierto la cabeza.

    Para este caso en concreto me viene bien, pero en otros casos, en el que requiero de una sesión para ejecutar comandos con -ScriptBlock sigue sin valerme. 

    Investigaré para buscar caminos alternativos a la utilización de -ScriptBlock para los otros casos. Pero tengo que tratar de aprender cómo puedo sacar el valor de una variable  que se utiliza dentro de un ScriptBlock, para tratarla fuera del ScriptBlock. 

    Gracias de nuevo, me has aportado darle otro enfoque al problema.

    2019年3月19日 19:29
  • Buenas,

    ¿Es necesario establecer una sesión remota abierta permanentemente?

    Podrías simplemente utilizar Invoke-Command, recoges los datos, generas tu variable en local y automáticamente se cierra la sesión remota.

    Por ejemplo:

    foreach ($ServerName in $Server)
    {
    
        $Machine = Invoke-Command -Credential $Cred -ComputerName $ServerName -ScriptBlock {
    
            [pscustomobject]@{
                IP = (Get-WmiObject -class win32_NetworkAdapterConfiguration -Filter 'ipenabled = "true"').ipaddress[0]
                ComputerName = $ServerName
                Vulnerable = $false
                TypeGPU = Get-WmiObject -class win32_VideoController -Property AdapterCompatibility
                NameGPU = Get-WmiObject -class win32_VideoController -Property Caption
                GPUVersion = Get-WmiObject -class win32_VideoController -Property DriverVersion
                Description = ""
            }
    
    
    
        }
    
        if(test-connection)
        {
            #Some Code
        }
    }


    • 已编辑 Jebisata 2019年3月21日 8:36
    • 已标记为答案 v3nt4n1t0 2019年3月31日 18:40
    2019年3月21日 8:35
  • Buenas, perdona por la tardanza, he estado liado estos días y no me he podido sentar con esto antes.

    - ¿Es necesario establecer una sesión remota abierta permanentemente?

    - Pues como lo has planteado, no. :-)

    He seguido tu consejo y ahora funciona como quería :- ). Salvo por un caso en concreto :-( . Me recoge todos los datos bien de todas las máquinas y me los guarda bien en el array $Output, salvo el de una máquina (la windows 7) que no me guarda los datos en el array $Output.

    Adjunto imágenes con el caso en concreto. Perdona que las adjunte así, no me deja añadirlas de otra forma hasta que mi cuenta no este verificada:

    https://ibb.co/60DrVvz
    https://ibb.co/RQQjLk6

    Por lo demás, todo correcto. ¡ Muchas Gracias ! Los consejos que me has dado me van a valer para mucho ! 

    Adjunto también enlace con el código, para no llenar todo el post de código. Por si le quieres echar un vistazo y ver cómo va:

    https://pastebin.com/zzr31FUH

    Siempre me queda esa sensación de que es probable de que se pueda hacer de una forma más correcta. jaja

    Gracias ! 

    Saludos

    2019年3月31日 19:16
  • Buenas,

    Encontré la solución al problema. Mejor tarde que nunca. 

    El problema estaba en que PSCustomObject se introdujo en PowerShell 3.0, de ahí que no funcione correctamente con la versión de PowerShell de las máquinas Windows 7 que disponía en mi dominio. Estas máquinas hacen uso de PowerShell 2.0.

    Para solucionar esto, obtuve la versión de PowerShell de cada máquina y añadí una condición. Dependiendo que versión tenga, crea el objeto con un método u otro. Adjunto código para visualizar las diferencia entre crear un PSObject de PowerShell 2.0 y un PSCustomObject de PowerShell 3.0 y versiones posteriores:

                        $psversion = Get-Host
    
                        if($psversion.Version.Major -lt 3){ #Si version de PowerShell menor que 3
                            New-Object -TypeName PSObject -Property @{
                                IP = (Get-WmiObject -class win32_NetworkAdapterConfiguration -Filter 'ipenabled = "true"').ipaddress[0]
                                ComputerName = [Environment]::GetEnvironmentVariable("ComputerName")
                                VulnerableDrivers = $false
                                VulnerableGeForceExperience = $VulnerableExperience
                                TypeGPU = Get-WmiObject  -class win32_VideoController -Property AdapterCompatibility
                                NameGPU = Get-WmiObject  -class win32_VideoController -Property Caption
                                GPUVersion = Get-WmiObject  -class win32_VideoController -Property DriverVersion
                                PING = "OK"
                                Description = $Description
                            }
                        }
                        else{
    
                            [pscustomobject]@{
                                IP = (Get-WmiObject -class win32_NetworkAdapterConfiguration -Filter 'ipenabled = "true"').ipaddress[0]
                                ComputerName = [Environment]::GetEnvironmentVariable("ComputerName")
                                VulnerableDrivers = $false
                                VulnerableGeForceExperience = $VulnerableExperience
                                TypeGPU = Get-WmiObject  -class win32_VideoController -Property AdapterCompatibility
                                NameGPU = Get-WmiObject  -class win32_VideoController -Property Caption
                                GPUVersion = Get-WmiObject  -class win32_VideoController -Property DriverVersion
                                PING = "OK"
                                Description = $Description
                            }
                        }



    Recordar que la versión de PowerShell 1 también trabaja de forma distinta con los PSObject. En caso necesario habría que añadir este método a la condición.



    • 已编辑 v3nt4n1t0 2020年6月1日 20:05 corrección ortográfica
    2020年6月1日 20:03