none
Custom Object returns with results condensed to one line RRS feed

  • Question

  • Not sure how to put this exactly. I have created a script that runs through our GPOs and compares them in a double foreach loop. To format the output to label every Setting that comes out as being similar with the GPos they are similar in I created a custom object, added members and then wrote the output. The problem is for each comparison it condenses all of the settings Paths and Diff type to just one write of the Custom Object. 

    Path      : {Computer Configuration|Policies|Administrative Templates|Citrix Components|Citrix Receiver|User authentication|Local user name and password|State, Computer Configuration|Policies|Administrative Templates|Citrix Components|Citrix Receiver|User authentication|Local user name and password|Enable pass-through authentication|State, Computer Configuration|Policies|Administrative Templates|Citrix Components|Citrix Receiver|User authentication|Local 
    user name and password|Allow pass-through authentication for all ICA connections|State, Computer Configuration|Policies|Administrative Templates|Citrix Components|Citrix Receiver|User authentication|Local user name and password|Use Novell Directory Server credentials|State...}
    DiffType  : {SameAsBase, SameAsBase, SameAsBase, SameAsBase...}
    DiffType2 : {None, None, None, None...}


    So it looks like this and not separated out in a way that exports to a csv nicely. Here is the Loop used to produce the output.

    ForEach($GPA in $gponameA) 
    {
        foreach($GPB in $gponameB) 
        {$Setting = compare-gpo -GpoNameA "$GPA" -GpoNameB "$GPB" | Where-Object {$_.DiffType -match "SameAsBase" -or $_.DiffType -match "Different*"}
        [GC]::Collect()
        
        $object = New-Object -Property @{
            GPO1 = $GPA.DisplayName 
            GPO2 = $GPB.DisplayName  
            Path = $Setting.Path  
            DiffType = $Setting.DiffType 
            DiffType2 = $Setting.DiffType2
    }
         
         Write-Output $object| Export-Csv C:\Users\innovate6563\Documents\GPOlinkComp.csv -Append
    [GC]::Collect()} 
    
    } 

    If anyone can point me to an article that can help me or can explain why it is condensing it under one entry I would greatly appreciate it. I am not sure how to look for solutions to an issue like this. Also if anyone sees a way to write this better please tell me. I am sure there is but I am still fairly new to scripting.

    Friday, November 20, 2015 3:02 PM

Answers

  • I think you are saying you want to output a new PSObject from the output of the Compare-Gpo command. Something like this, perhaps (not tested):


    foreach ( $GPA in $gponameA ) {
      foreach ( $GPB in $gponameB ) {
        Compare-Gpo -GpoNameA "$GPA" -GpoNameB "$GPB" | Where-Object { $_.DiffType -match "SameAsBase" -or $_.DiffType -match "Different*" } | ForEach-Object {
          New-Object -Property @{
              GPO1 = $GPA.DisplayName 
              GPO2 = $GPB.DisplayName  
              Path = $_.Path  
              DiffType = $_.DiffType 
              DiffType2 = $_.DiffType2
        }
      }
    }
    


    -- Bill Stewart [Bill_Stewart]

    • Marked as answer by Tohrment Friday, November 20, 2015 9:16 PM
    Friday, November 20, 2015 6:59 PM
    Moderator

All replies

  • Remove


    $object =
    

    and the Write-Output line.

    You also likely don't need


    [GC]::Collect()

    A primer on how PowerShell uses objects may be helpful:

    Windows IT Pro - PowerShell: Objects and Output


    -- Bill Stewart [Bill_Stewart]

    Friday, November 20, 2015 3:15 PM
    Moderator
  • I made the edits that you suggested and read the article. I still can't seem to get it to create a new object for each setting it finds. I would be just as fine creating a new property for each setting it sends through but can't seem to get it to want to do that either. I just need the output to be exportable to csv where I can open it in excel and it not just have System.Object/String[] in the Path column.
    Friday, November 20, 2015 4:44 PM
  • I think you are saying you want to output a new PSObject from the output of the Compare-Gpo command. Something like this, perhaps (not tested):


    foreach ( $GPA in $gponameA ) {
      foreach ( $GPB in $gponameB ) {
        Compare-Gpo -GpoNameA "$GPA" -GpoNameB "$GPB" | Where-Object { $_.DiffType -match "SameAsBase" -or $_.DiffType -match "Different*" } | ForEach-Object {
          New-Object -Property @{
              GPO1 = $GPA.DisplayName 
              GPO2 = $GPB.DisplayName  
              Path = $_.Path  
              DiffType = $_.DiffType 
              DiffType2 = $_.DiffType2
        }
      }
    }
    


    -- Bill Stewart [Bill_Stewart]

    • Marked as answer by Tohrment Friday, November 20, 2015 9:16 PM
    Friday, November 20, 2015 6:59 PM
    Moderator
  • That is actually the conclusion I finally came to after just messing around with the where the Custom Object would bring its values together at. Just got back from lunch to find this and I really appreciate the help. The [GC]::Collect is required in my case because it burns through RAM like nobodies business and since I am an intern and using a laptop with only 4GB of RAM it crashes  my system without those in there. 

    One thing that surprises me is there isn't a good script out there to compare all GPOs in the domain which was what I was tasked with. I am having to use a combination of a cmdlet that is limited to 4 GPOs at a time and the script above to run through them 2 at a time just to get a good report.

    Again, I thank you for your help and hope you have a great rest of the day and a great weekend!

    Friday, November 20, 2015 7:45 PM
  • This method will reduce your memory footprint.  It avoids constant generation of the hash which I likely what is causing you an issue.   It also passes the objects to the file and allows them to be destroyed by the sysem.  YOU are accumulating all of them in memory before you write. 

    $p=@{
    	GPO1 = $null
    	GPO2 = $null
    	Path = $null
    	DiffType = $null
    	DiffType2 = $null
    }
    
    $gponameA |
    ForEach-Object{
    	$GPA = $_
    $p.Keys.Clone()|%{$p.Set_Item($_,$null)} # clear hash $p.GPO1 = $GPA.DisplayName foreach ($GPB in $gponameB) { $p.GPO2 = $GPB.DisplayName Compare-Gpo -GpoNameA "$GPA" -GpoNameB "$GPB" | Where-Object { $_.DiffType -match "SameAsBase" -or $_.DiffType -match "Different*" } | ForEach-Object { $p.Path = $_.Path $p.DiffType = $_.DiffType $p.DiffType2 = $_.DiffType2 New-Object -Property $p } } } | Export-Csv C:\Users\innovate6563\Documents\GPOlinkComp.csv


    \_(ツ)_/


    • Edited by jrv Friday, November 20, 2015 8:54 PM
    Friday, November 20, 2015 8:40 PM
  • Just for kicks and giggles I ran your version to see after contemplating how it would be different and it still ran the RAM through the roof. I think it might be a memory leak in the application that gives the cmdlet needed for the compare. Its no biggie. In the end it completes the task it was written for and my system doesn't crash halfway through. Though it may not be pretty with those Collects through there it gets the job done.

    Thank you both for your help!

    Friday, November 20, 2015 9:16 PM
  • You may also be missing patches for Net.

    Why not just fix the GPO tool?


    \_(ツ)_/

    Friday, November 20, 2015 9:26 PM
  • Also note that there is no reason to worry about memory usage.  PS will adjust for it.  If you are running out of paging space then increase you page file.

    If no other processes require memory then PS is free to use as much as it can get. It will give back if needed. Only hands and contexts will cause a crash. If the CmdLet is leaking handles then you might have an issue.  I can't believe you have that many GPOs to match although you are doing an N*M calculation.  That is n times m.  If you have 50 in the first group and 50 in the second you will have to manipulate 2500 files.  File descriptors use main memory and are not swappable.


    \_(ツ)_/

    Friday, November 20, 2015 9:34 PM
  • Luckily there is only 23 in the first and 22 in the second. I didn't develop the tool and am no programmer. This is really just a one off thing to correct mistakes made by the previous supervisor who set most of the original GPOs up. It was also used as a learning experience because I had never used custom PSObjects to create a custom output and had never nested a foreach loop in another foreach loop. I learned a lot in this venture which is my ultimate goal but getting to accomplish a task at the same time is really nice too.

    Friday, November 20, 2015 10:46 PM
  • Good.  It is a good learning tool.  If you track down where the memory leak is you will also learn a bunch.


    \_(ツ)_/

    Friday, November 20, 2015 10:51 PM