Within Powershell, the CopyHere method for the Shell-Application Namespace is asynchronous. My main goal with this is to convert a KML file to a KMZ file. The process of doing this is to create a ZIP file with the same name, copy the KML into the KMZ (compresses the file) and then rename the ZIP to KMZ. Unfortunately, being asynchronous means the rename function is being called before the CopyHere method is completed. I have found many examples of solving this. The cleanest one I found is below:
$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"))
This responds with the following error:
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
Am I misusing the Item method for this particular package? I am confused why something that "appears" to be neatly done is not working. I have also tried the snippet of code provided Here. It also complains about the .Item method in this particular situation.
The issue i ran into was trying to find away to check on zip status.
So instead i did a trigger for a while that would fire ...If the Zipfile was openable and the File name was inside.
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"
User contributions licensed under CC BY-SA 3.0