2017-12-15 20 views
0

In Powershell ist die CopyHere-Methode für den Shell-Application-Namespace asynchron. Mein Hauptziel dabei ist, eine KML-Datei in eine KMZ-Datei zu konvertieren. Dazu erstellen Sie eine ZIP-Datei gleichen Namens, kopieren die KML in die KMZ (komprimiert die Datei) und benennen die ZIP-Datei in KMZ um. Asynchron bedeutet leider, dass die Umbenennungsfunktion aufgerufen wird, bevor die CopyHere-Methode abgeschlossen ist. Ich habe viele Beispiele gefunden, um das zu lösen. Die sauberste fand ich unter:PowerShell ZIP CopyHier wirkendes entgegenwirkendes asynchrones Verhalten

$kmlPath = $global:directoryPath + "Test.kml" 
$zip = $global:directoryPath + "Test.zip" 
New-Item $zip -ItemType file 
$shellApplication = new-object -com shell.application 
$zipPackage = $shellApplication.NameSpace($zip) 
$zipPackage.CopyHere($kmlPath, 16) 

while($zipPackage.Items().Item($zip.Name) -Eq $null) 
{ 
    start-sleep -seconds 1 
    write-host "." -nonewline 
} 
write-host "." 
Rename-Item -Path $zip -NewName $([System.IO.Path]::ChangeExtension($zip, ".kmz")) 

Dieser reagiert mit dem folgenden Fehler:

Exception calling "Item" with "1" argument(s): "Not implemented (Exception from HRESULT: 0x80004001 (E_NOTIMPL))" + while($zipPackage.Items().Item($zip.Name) -Eq $null) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : NotSpecified: (:) [], MethodInvocationException + FullyQualifiedErrorId : ComMethodTargetInvocation

Bin ich die Item-Methode für dieses spezielle Paket zu mißbrauchen? Ich bin verwirrt, warum etwas, das "sauber" erscheint, nicht funktioniert. Ich habe auch das Code-Schnipsel Here versucht. Es beschwert sich auch über die .Item-Methode in dieser speziellen Situation.

Antwort

1

Das Problem, das ich rannte, war zu versuchen, weg zu finden, um auf Reißverschlussstatus zu überprüfen.

Also stattdessen habe ich einen Trigger für eine Weile, die ausgelöst würde ... Wenn die Zipfile war zu öffnen und der Dateiname war drin.

function kml_to_kmz([string]$kmlPath){ 
    [Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem') 
    $kmlInfo = Get-ChildItem -Path $kmlPath 
    $zipLocation = ($kmlInfo.Directory.FullName + '\' + $kmlInfo.Name.Remove($kmlInfo.Name.LastIndexOf('.')) + '.zip') 
    New-item $zipLocation 
    ((new-object -com shell.application).NameSpace($zipLocation)).CopyHere($kmlPath, 16) 
    $trigger = $false 
    while ($trigger -eq $false){ 
     try{ 
      $zip = [IO.Compression.ZipFile]::OpenRead($zipLocation) 
      If(($zip.Entries | %{$_.Name}) -contains $kmlInfo.Name){ 
       $zip.Dispose(); 
       $trigger = $true 
       break; 
      } 

     }catch{} 
     start-sleep -seconds 1 
     write-host "." -nonewline 
    } 
    [IO.Compression.ZipFile]::OpenRead($zipLocation).Dispose() 
    Rename-Item -Path $zipLocation -NewName $([System.IO.Path]::ChangeExtension($zipLocation, '.kmz')) 
} 

kml_to_kmz -kmlPath "C:\Users\Default\Desktop\Test.kml" 
+0

Dies funktionierte tatsächlich perfekt. Ich musste "-ItemType-Datei" zur Instanziierung für neue Objekte hinzufügen, aber das war eine schnelle Lösung (andernfalls wurde ich aufgefordert, einen Typ einzugeben). Ich habe bemerkt, dass die Ausgabe in ISE jetzt eine Reihe von globalen Konfigurationen ausspuckt (CodeBase, FullName, EntryPoint, DefinedTypes und wie 40 andere). Ich bin mir nicht sicher, welcher Teil des Codes all diese Ausgaben ausgibt, aber es ist definitiv störend. Irgendwelche Ideen? –

+0

Die Zeile '[Reflection.Assembly] :: LoadWithPartialName (' System.IO.Compression.FileSystem ')' speichert eine ausführliche Ausgabe der Assembly-Parameter in der Konsole. Ich habe es modifiziert, indem ich '| Out-Null 'bis zum Ende, um die Ausgabe zu maskieren. Alles funktioniert perfekt noch. –

+0

Froh, dass es für dich funktioniert :) – ArcSet

Verwandte Themen