locked
Export-CSV not working as expected RRS feed

  • Question

  • I'm running a script to remotely grab installed software from the registry. (I like this method over "Get-WmiObject win32_Product" and other methods.)I really want the computername to be the first column in the CSV. The following script works, but when I add "$entry | Export-CSV c:\temp\SoftwareINVviaREG_$((Get-Date).ToString('MM-dd-yyyy')).csv -append -force -NoTypeInformation" I don't get the computername as defined in my script. Instead I get "PSPath PSParentPath PSChildName PSDrive PSProvider ReadCount Length
    C:\temp\systems.txt C:\temp systems.txt C Microsoft.PowerShell.Core\FileSystem 3 6"????? I'm totally stuck and need a guru to help me out. Thanks! I'm new to powershell.

    Function CheckPing {$result = Test-Connection -count 1 -computer $entry -quiet
    IF ($result -eq "True") {RunBody}
    ELSE
    {echo $entry >> C:\temp\offline.txt}
    }

    Function RunBody
    {
    Get-ChildItem hklm:\software\microsoft\windows\currentversion\uninstall | ForEach-Object {Get-ItemProperty $_.pspath} |
    Where-Object {$_.DisplayName -and !$_.SystemComponent -and !$_.ReleaseType -and !$_.ParentKeyName -and ($_.UninstallString -or $_.NoRemove)} |
    Export-CSV c:\temp\SoftwareINVviaREG_$((Get-Date).ToString('MM-dd-yyyy')).csv -append -force -NoTypeInformation
    }
    cls

    Write-Host "Scanning Systems for Inventory Data....." -ForegroundColor Green
    $computers = get-content c:\temp\systems.txt
    ForEach ($entry in $computers){CheckPing}

    Wednesday, November 7, 2012 12:58 AM

Answers

  • You need to pass parameters to your functions... and your functions need to read those parameters

    Pass a paramter to a function:

    ForEach ($entry in $computers){CheckPing $entry} #$entry is value we want the function to use

    The Function reads the parameter value:

    Function CheckPing {

    Param ([string]$entry) #the function gets the value and assigns it to variable $entry

    $result=Test-Connection $entry ...

    }

    See the help files...

    get-help about_functions

    get-help about_advanced_functions

    You need to change the RunBody function to accept the current computername as a parameter.

    Then you'll need to alter your code to read the registry on a remote machine specified by the computername parameter.

    Here's a function that will do that: You just need to alter the logic to get the values and criteria you want.

    function GetInstalledProgs{
    param(
        [string]$Srv
        )
    $mydata=@()
    $key = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"
    $type = [Microsoft.Win32.RegistryHive]::LocalMachine
    $regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($type, $Srv)
    $regKey = $regKey.OpenSubKey($key)
    
    foreach($subkey in $regkey.GetSubkeyNames()){
        foreach($name in $subkey){
            $r1=$regkey.opensubkey($name)
            $roger='' | Select Computer,DisplayName,DisplayVersion
            [void]$r1.GetValueNames()
            foreach($r2 in $r1){
                if($r2.GetValue('DisplayName')){
                $roger.Computer=$Srv
                $roger.DisplayName=$r2.GetValue('DisplayName')
                $roger.DisplayVersion=$r2.GetValue('DisplayVersion')
                $mydata+=$roger
                }
            }
        }
        }
    return $mydata
    }    

    The object returned by the above function contains the computer name.

    Just use Select Computer,DisplayName,DisplayVersion | Export-Csv.... to get the columns in the order you want.

    Hope that helps.


    Admiral Ackbar says...

    • Proposed as answer by Yan Li_ Wednesday, November 7, 2012 9:41 AM
    • Marked as answer by zperryz Thursday, November 8, 2012 7:14 PM
    Wednesday, November 7, 2012 1:30 AM
  • Make sure the Remote Registry service is running on the target computers:

    
    Get-Service remoteregistry -ComputerName <Remote Computer>


    Grant Ward, a.k.a. Bigteddy

    Also, make sure there are no spaces after the computer names in your input text file...

    $computers = get-content c:\temp\systems.txt | ForEach{$_.Trim()}
     

    Powershell will include any spaces in the string and can result in the error you are getting.

    Admiral Ackbar says...

    • Marked as answer by zperryz Thursday, November 8, 2012 7:14 PM
    Thursday, November 8, 2012 5:52 PM

All replies

  • You need to pass parameters to your functions... and your functions need to read those parameters

    Pass a paramter to a function:

    ForEach ($entry in $computers){CheckPing $entry} #$entry is value we want the function to use

    The Function reads the parameter value:

    Function CheckPing {

    Param ([string]$entry) #the function gets the value and assigns it to variable $entry

    $result=Test-Connection $entry ...

    }

    See the help files...

    get-help about_functions

    get-help about_advanced_functions

    You need to change the RunBody function to accept the current computername as a parameter.

    Then you'll need to alter your code to read the registry on a remote machine specified by the computername parameter.

    Here's a function that will do that: You just need to alter the logic to get the values and criteria you want.

    function GetInstalledProgs{
    param(
        [string]$Srv
        )
    $mydata=@()
    $key = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"
    $type = [Microsoft.Win32.RegistryHive]::LocalMachine
    $regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($type, $Srv)
    $regKey = $regKey.OpenSubKey($key)
    
    foreach($subkey in $regkey.GetSubkeyNames()){
        foreach($name in $subkey){
            $r1=$regkey.opensubkey($name)
            $roger='' | Select Computer,DisplayName,DisplayVersion
            [void]$r1.GetValueNames()
            foreach($r2 in $r1){
                if($r2.GetValue('DisplayName')){
                $roger.Computer=$Srv
                $roger.DisplayName=$r2.GetValue('DisplayName')
                $roger.DisplayVersion=$r2.GetValue('DisplayVersion')
                $mydata+=$roger
                }
            }
        }
        }
    return $mydata
    }    

    The object returned by the above function contains the computer name.

    Just use Select Computer,DisplayName,DisplayVersion | Export-Csv.... to get the columns in the order you want.

    Hope that helps.


    Admiral Ackbar says...

    • Proposed as answer by Yan Li_ Wednesday, November 7, 2012 9:41 AM
    • Marked as answer by zperryz Thursday, November 8, 2012 7:14 PM
    Wednesday, November 7, 2012 1:30 AM
  • Alternatively, if you have WinRM/PSRemoting configured and working on your remote computers, you could do this...

    $scriptblock={Get-ChildItem hklm:\software\microsoft\windows\currentversion\uninstall | ForEach-Object {Get-ItemProperty $_.pspath} |
        Where-Object {$_.DisplayName -and !$_.SystemComponent -and !$_.ReleaseType -and !$_.ParentKeyName -and ($_.UninstallString -or $_.NoRemove)}}
    
    $myresult=Invoke-Command -Computer @('computer1','computer2') -Scriptblock $scriptblock |
        Select PSComputerName,DisplayName,UninstallString,NoModify,NoRepair,PSPath,PSParentPath,PSChildName,PSProvider
     
    $myresult | Export-CSV c:\temp\SoftwareINVviaREG_$((Get-Date).ToString('MM-dd-yyyy')).csv -append -force -NoTypeInformation

    See the following help files on remoting and setting it up:

    get-help about_PSSessions

    get-help about_Remote_Requirements

    get-help about_Remote_FAQ

    get-help about_Remote_Troubleshooting

    PSRemoting takes a bit of effort to set up, but it's amazingly fast and flexible for tasks involving lots of remote computers.


    Admiral Ackbar says...

    Wednesday, November 7, 2012 3:26 AM
  • I really like what you have shown me here, but its not working for me on remote computers. I've done the following:

    function GetInstalledProgs{
    param(
        [string]$Srv
        )
    $mydata=@()
    $key = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"
    $type = [Microsoft.Win32.RegistryHive]::LocalMachine
    $regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($type, $Srv)
    $regKey = $regKey.OpenSubKey($key)

    foreach($subkey in $regkey.GetSubkeyNames()){
        foreach($name in $subkey){
            $r1=$regkey.opensubkey($name)
            $roger='' | Select Computer,DisplayName,DisplayVersion
            [void]$r1.GetValueNames()
            foreach($r2 in $r1){
                if($r2.GetValue('DisplayName')){
                $roger.Computer=$Srv
                $roger.DisplayName=$r2.GetValue('DisplayName')
                $roger.DisplayVersion=$r2.GetValue('DisplayVersion')
                $mydata+=$roger
                }
            }
        }
        }
    return $mydata
    }
    $computers = get-content c:\temp\systems.txt
    ForEach ($Srv in $computers){GetInstalledProgs $Srv}

    But I get the following Error:

    Exception calling "OpenRemoteBaseKey" with "2" argument(s): "The network path was not found.
    "
    At C:\temp\test.ps1:8 char:1
    + $regKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($type, $Srv)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
        + FullyQualifiedErrorId : IOException
     
    You cannot call a method on a null-valued expression.
    At C:\temp\test.ps1:9 char:1
    + $regKey = $regKey.OpenSubKey($key)
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidOperation: (:) [], RuntimeException
        + FullyQualifiedErrorId : InvokeMethodOnNull

    Thursday, November 8, 2012 3:22 PM
  • Make sure the Remote Registry service is running on the target computers:

    
    Get-Service remoteregistry -ComputerName <Remote Computer>


    Grant Ward, a.k.a. Bigteddy

    Thursday, November 8, 2012 4:34 PM
  • Make sure the Remote Registry service is running on the target computers:

    
    Get-Service remoteregistry -ComputerName <Remote Computer>


    Grant Ward, a.k.a. Bigteddy

    Also, make sure there are no spaces after the computer names in your input text file...

    $computers = get-content c:\temp\systems.txt | ForEach{$_.Trim()}
     

    Powershell will include any spaces in the string and can result in the error you are getting.

    Admiral Ackbar says...

    • Marked as answer by zperryz Thursday, November 8, 2012 7:14 PM
    Thursday, November 8, 2012 5:52 PM
  • ForEach{$_.Trim()}
     

    For hand-edited input files... don't use Get-Content without that!

    (and Set-Content and Add-Content...)

    Friday, November 9, 2012 3:26 AM