none
Powershell Set-Content fails RRS feed

  • Frage

  • Hi all, 

    I am new to powershell and want to copy logfiles from one directory, change some contents and write back the changed logfile to a destination directory. My script looks like this: It works fine when I don't include the Set-Content statement. The displayed path and filenames are correct.  Executing the  set-content statement leads to an error (see blow), also | out-file $outputfile doesn't work.  Any help or suggestions are welcome. 

    function test1 

    {
        param
        (
            [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
            [string]
            $InputPath,

            [Parameter(Mandatory=$true, ValueFromPipeline=$true)]
            [string]
            $OutputPath

        )

        process
        {
            $OutputFile = " "

            Get-ChildItem -Path $InputPath\* -Include *.log |  
              ForEach-Object { 
                "processing dir \ file: $_"
                $FileName = $_.name 

                "processing File : $Filename"
                $OutputFile = $OutputPath+"\"+$FileName
                "Output Path & File : $OutputFile"

                Get-Content $_ |
                ForEach-Object {
                  $Line = $_ 
                  ### more procssing  here 
                } 
              } |  Set-Content -Path $OutputFile
        }  
    }

    test1 C:\qv\InputLogfiles C:\qv\OutputLogfiles 
    Set-Content : Could not find a part of the path 'C:\Users\son\'.
    In Zeile:33 Zeichen:16
    +           } |  Set-Content -Path $OutputFile
    +                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : NotSpecified: (:) [Set-Content], DirectoryNotFoundException
        + FullyQualifiedErrorId : System.IO.DirectoryNotFoundException,Microsoft.PowerShell.Commands.SetContentCommand

     

    Siegmund Sonntag

    • Verschoben Alex Pitulice Donnerstag, 30. Mai 2013 12:41 Verschoben
    Donnerstag, 23. Mai 2013 09:19

Antworten

  • Hallo Siegmund, aus deinem Namen schließe ich mal das du deutsch sprichst.

    Ein paar Anmerkungen zu deinem Script:

    - Du solltest die Pipeline nur dort benutzen wo es Sinn macht. In Scripten tut es das meistens nicht. :)  Die Pipeline-Cmdlets sind prinzipbedingt teilweise sehr langsam. Z.b. ist foreach-object etwa 10-12 mal so langsam wie foreach ($x in $y) ...

    - dein Set-Content - Statement ist an der falschen Stelle, es gehört eine Zeile nach oben, ans Ende der Foreach-object-Klammer

    - Du verarbeitest deinen Text zwar irgendwie (leider nicht gepostet), aber du weist das Ergebnis $line zu. Per Pipeline wird aber weiterhin $_ an Out-Content weitergereicht, deshalb würde dort eh nicht das ankommen was du möchtest. 
    Ein Beispiel zum Verständnis:

    $a ="wort","wort-B"
    
    # das hier kann nicht gehen, da du nicht das Pipelinelement $_ verabeitest, sondern $line
    $a | ForEach-Object {  $line = $_.replace("wort","test1") } | Out-Host 
    
    # so gehts
    $a | ForEach-Object {  $_.replace("wort","test2") } | Out-Host 

     

    Vorschlag für dein Script:

     

    function test1 {
    	param  (
            [Parameter(Mandatory=$true, ValueFromPipeline=$true)][string]$InputPath,
            [Parameter(Mandatory=$true, ValueFromPipeline=$true)][string]$OutputPath
        )
    
        process {
    		# lese Liste der Quelldateien
            $sourcefiles = Get-ChildItem -Path $InputPath\* -Include *.log 
    		if (!($sourcefiles)) { Write-Host "Keine Logfiles im Quellpfad!" ; return}
    		
    		# einmalige Ausgabe des Quellpfades reicht, oder? :)
    		Write-host "processing dir: $inputpath `n"
    		
              ForEach ( $srcFile in $sourcefiles) {
    			$OutputFile = $OutputPath+"\"+$srcFile.name
    			
                Write-host "processing File : $($srcFile.name) `nOutput Path & File : $OutputFile"            
    			
    			# Ausgabearray erstellen (Sammlung von Objekten, in diesem Fall Textzeilen)
    			$Output = @()
    			
    			# lies Quellfile content
                $content = Get-Content $srcFile
    			 Foreach ($line in $content) {  
    			 	# processing 
    				# .....
    				
    				# die verarbeiteten Zeilen wieder zu einer Ausgabevariable zusammenführen!
    				$Output += $Line
    			}
    			# Ausgabe eines verarbeiteten Files
    			Set-Content -Path $OutputFile -Value $Output
              }  
    		  
        }  
    }
    
    test1 D:\tmp\1 D:\tmp\2

     

    Grüße, Denniver


    Blog: http://bytecookie.wordpress.com

    Hilf mit und markiere hilfreiche Beiträge als "Hilfreich" und Beiträge die deine Frage ganz oder teilweise beantwortet haben als "Antwort".

    Samstag, 1. Juni 2013 11:51
    Moderator

Alle Antworten

  • Hallo Siegmund, aus deinem Namen schließe ich mal das du deutsch sprichst.

    Ein paar Anmerkungen zu deinem Script:

    - Du solltest die Pipeline nur dort benutzen wo es Sinn macht. In Scripten tut es das meistens nicht. :)  Die Pipeline-Cmdlets sind prinzipbedingt teilweise sehr langsam. Z.b. ist foreach-object etwa 10-12 mal so langsam wie foreach ($x in $y) ...

    - dein Set-Content - Statement ist an der falschen Stelle, es gehört eine Zeile nach oben, ans Ende der Foreach-object-Klammer

    - Du verarbeitest deinen Text zwar irgendwie (leider nicht gepostet), aber du weist das Ergebnis $line zu. Per Pipeline wird aber weiterhin $_ an Out-Content weitergereicht, deshalb würde dort eh nicht das ankommen was du möchtest. 
    Ein Beispiel zum Verständnis:

    $a ="wort","wort-B"
    
    # das hier kann nicht gehen, da du nicht das Pipelinelement $_ verabeitest, sondern $line
    $a | ForEach-Object {  $line = $_.replace("wort","test1") } | Out-Host 
    
    # so gehts
    $a | ForEach-Object {  $_.replace("wort","test2") } | Out-Host 

     

    Vorschlag für dein Script:

     

    function test1 {
    	param  (
            [Parameter(Mandatory=$true, ValueFromPipeline=$true)][string]$InputPath,
            [Parameter(Mandatory=$true, ValueFromPipeline=$true)][string]$OutputPath
        )
    
        process {
    		# lese Liste der Quelldateien
            $sourcefiles = Get-ChildItem -Path $InputPath\* -Include *.log 
    		if (!($sourcefiles)) { Write-Host "Keine Logfiles im Quellpfad!" ; return}
    		
    		# einmalige Ausgabe des Quellpfades reicht, oder? :)
    		Write-host "processing dir: $inputpath `n"
    		
              ForEach ( $srcFile in $sourcefiles) {
    			$OutputFile = $OutputPath+"\"+$srcFile.name
    			
                Write-host "processing File : $($srcFile.name) `nOutput Path & File : $OutputFile"            
    			
    			# Ausgabearray erstellen (Sammlung von Objekten, in diesem Fall Textzeilen)
    			$Output = @()
    			
    			# lies Quellfile content
                $content = Get-Content $srcFile
    			 Foreach ($line in $content) {  
    			 	# processing 
    				# .....
    				
    				# die verarbeiteten Zeilen wieder zu einer Ausgabevariable zusammenführen!
    				$Output += $Line
    			}
    			# Ausgabe eines verarbeiteten Files
    			Set-Content -Path $OutputFile -Value $Output
              }  
    		  
        }  
    }
    
    test1 D:\tmp\1 D:\tmp\2

     

    Grüße, Denniver


    Blog: http://bytecookie.wordpress.com

    Hilf mit und markiere hilfreiche Beiträge als "Hilfreich" und Beiträge die deine Frage ganz oder teilweise beantwortet haben als "Antwort".

    Samstag, 1. Juni 2013 11:51
    Moderator
  • danke, sehr zufrieden mit der Antwort.

    viele Grüße

    sonny


    Siegmund Sonntag

    Montag, 3. Juni 2013 16:17