# Nur bestimmte Zip-Files entpacken



## amn.ssy (6. Juni 2014)

Hallo,

ich versuche derzeit eine Batch in VBS umzuschreiben und habe dabei schon durchaus ein paar Fortschritte gemacht 
An der Folgenden Sache bleiche ich jedoch hängen:


```
set In=%wks%\GetInput.vbs
>%In% echo Set args=WScript.Arguments:WScript.Echo InputBox(args(0), args(1))
:Loop
set  "ym=" & for /f "delims=" %%i in ('cscript //nologo %In% "Input yymm" "Input Year and Month" ""') do set "ym=%%i"
If not defined ym goto :Loop

call :UnzipMSG

for %%f in (%data%%ym%*.zip) do (
set "fname=%%~nxf"
  if /i "!fname:~-7!" == "com.zip" (
  "%ext%7z" e "%%f" -y -o"%inc%*"
  ) else (
  "%ext%7z" e "%%f" -y -o"%inr%*" @%cfg%zipfilelist.txt
  )
) >>NUL
```

Bevor der ab gebildete Code in Aktion tritt werden alle Zip-Dateien ermittelt bei denen jeweils die ersten 4 Zeichen gleich sind und angezeigt. Über ein Input können dann diese 4 Zeichen eingeben werden und 7z entpackt die Dateien analog der zipfilelist in die entsprechenden Ordner.

Nun möchte ich gerne das ganze in VBS überführen und dabei soll folgendes passieren:
- allen Zip-Dateien in \Data ermitteln deren erste 4 Zeichen gleich sind
- analog eines Teil des Dateinames der Zip im vordefinierte Ordner ein Unterordner erstellen und dort entpacken.
- endet der Zip-Name mit com.zip ändert sich der vordefinierte Ordner

Beispiel:
Im Verzeichnis Data liegen z.B 12 Zip-Dateien. Jeweils 4 beginnen mit den gleichen Zeichen
(1101 xyz 650.zip, 1101 xyz 660.zip, 1101 xyz 670.zip, 1101 xyz 670 com.zip)
Nun sollen alle Zip-Dateien die mit 1101 beginnen entpackt werden in die Unterverzeichnisse
\in\raw\xyz 650\, in\raw\xyz 660\, in\raw\xyz 670\, in\com\xyz 670 com\.
Dabei existiert bislang nur das Verzeichnis \in. Die anderen Verzeichnisse wie xyz 650 oder xyz 670 com müßten erstellt werden.

Der Input könnte erstmal entfallen, wichtig wäre daß die ersten passenden Zip-Files entpackt werden.
Im spätern Verlauf, wenn z.B. 1201, 1301, usw. da sind, müßte ich mich um einen Loop über das gesammte Script kümmern. Bis dahin kann man das Programm ja auch neu starten  ;-)

Bis jetzt sieht das ganze so aus:


```
lw = Left( WScript.ScriptFullName, 2 )
root = lw & "\gmd"
bin = root & "\bin"
cfg = bin & "\cfg"
ext = bin & "\ext"
lg = bin & "\log"
ton = chr(007)

Set WshShell = CreateObject("WScript.Shell")
WshShell.Run "cscript //nologo " & bin & "\getData.vbs " & cfg & "\xyz650.ini",0,true
WshShell.Run "cscript //nologo " & bin & "\getData.vbs " & cfg & "\xyz660.ini",0,true
WshShell.Run "cscript //nologo " & bin & "\getData.vbs " & cfg & "\xyz670.ini",0,true
WshShell.Run "cmd /c @echo " & ton, 0
WshShell.Run bin & "\GMDevents.hta",0,true
Set WshShell = nothing
```

Soviel zur Theorie - leider endets dann auch schon 

LG
amn.ssy


----------



## Yaslaw (6. Juni 2014)

Hast du schon Erfahrung mit VBS?
Wie sehen denn deine ersten Versuche für dieses Script aus?

Wenn du eine fertige Version haben willst, denn verschieben wir den Thread zu den Stellenausschreibungen


----------



## amn.ssy (6. Juni 2014)

Hallo Yaslaw,

Erfahrungen in VBS hab ich dahingehend was ich im Netz finde und halbwegs verstehe.
Meine ersten Versuche hab ich gerade an den Eingangsthread angefügt.

Ich glaub für 'ne "Stellenausschreibung" reicht nicht ganz ;-)

Gruß
amn.ssy


----------



## amn.ssy (6. Juni 2014)

n'Abend!

mit meiner Anfrage hangel ich mich langsam vor:

```
Dim fso, folder, file

lw = Left( WScript.ScriptFullName, 2 )
root = lw & "\gmd"
bin = root & "\bin"
cfg = bin & "\cfg"
ext = bin & "\ext"
lg = bin & "\log"
data = root & "\data"
input = root & "\input"
inc = input & "\coa"
inr = input & "\raw"
ext = "zip"
i = 0

Set fso = CreateObject("Scripting.Filesystemobject")
Set folder = fso.GetFolder(data)
ForEach file In folder.Files
If fso.GetExtensionName(file) = ext then
      i = i + 1
   If DataSet = "" then
    DataSet = Left (fso.GetFileName(file),4)
    Product = Mid (fso.GetFileName(file),5,11)
    ProdCoA = Right (fso.GetFileName(file),7)
   Else
   DataSet = DataSet
   Product = Product
   ProdCoA = ProdCoA
   Endif
EndIf
Next

Set WshShell = CreateObject("WScript.Shell")
If i > 0 Then

                WshShell.Run ext & "\7z e " & file & " -y -o" & inc,0,true
Else
                WshShell.Run ext & "\7z e " & file & " -y -o" & inr,0,true
End If
Else
MsgBox"No Zip-File(s)"
EndIf
```

Das ist bestimmt wahrlich nicht der Weisheit letzter Schluss und geht bestimmt auch noch besser.
Hängen bleib ich jetzt an der korrekten Implementierung und Syntax für 7z.

Gruß
amn.ssy


----------



## Zvoni (6. Juni 2014)

Brrrrr.....

Mich schauderts jedesmal, wenn ich solche verrenkungen sehe.

Wenn die namensstruktur der zip-dateien wie oben im muster erwähnt immer gleich ist (vor allem die leerzeichen!), dann würde ich pro ermitteltem dateinamen die split-funktion nehmen mit leerzeichen als trennzeichen.

Im resultierenden array ist member 0 deine ersten stellen des namens (im beispiel 1101), und im letzten member (UBound-funktion) kann geprüft werden ob die datei auf com.zip endet


----------



## amn.ssy (6. Juni 2014)

Hallo Zvoni,

ich sag doch: "ist nicht der Weisheit letzter Schluss!"
Hast du ein Beispiel parat, an dem ich das für meine Anforderung umsetzen kann oder mich dem zumindest etwas näher bringt?

Gruß
amn.ssy


----------



## amn.ssy (6. Juni 2014)

Hallo,

ich hab den Vorschlag von "Zvoni" aufgegriffen und umgesetzt:


```
Dim fso, folder, file, ZipParts

lw = Left( WScript.ScriptFullName, 2 )
root = lw & "\gmd"
bin = root & "\bin"
cfg = bin & "\cfg"
ext = bin & "\ext"
lg = bin & "\log"
data = root & "\data"
input = root & "\input"
inc = input & "\coa"
inr = input & "\raw"

ton = chr(007)
ext = "zip"
i = 0

Call Logging ("Start program")

Set fso = CreateObject("Scripting.Filesystemobject")
Set folder = fso.GetFolder(data)

ForEach fileIn folder.Files
If fso.GetExtensionName(file) = extThen
            ZipParts = Split(fso.GetFileName(file)," ")
            Pstrenght = Left (ZipParts(2),3)
            i = i + 1
EndIf
Next

If i = 0Then
Call Logging ("Zip-File(s) not available")
Else
Call Logging ("process " & ZipParts(1) & " of " & ZipParts(0))
EndIf

Set WshShell = CreateObject("WScript.Shell")
If i > 0Then
If ZipParts(2) = "com.zip"Then
            WshShell.Run ext & "\7z.exe e " & data & "\" & ZipParts(0)& "*.zip -y -o" & inc & "\" & ZipParts(1) & Pstrenght,0,True
Else
            WshShell.Run ext & "\7z.exe e " & data & "\" & ZipParts(0)& "*.zip -y -o" & inr & "\" & ZipParts(1) & Pstrenght,0,True
EndIf
EndIf

WshShell.Run"cscript //nologo " & bin & "\getData.vbs " & cfg & "\xyz650.ini",0,true
WshShell.Run"cscript //nologo " & bin & "\getData.vbs " & cfg & "\xyz660.ini",0,true
WshShell.Run"cscript //nologo " & bin & "\getData.vbs " & cfg & "\xyz670.ini",0,true
WshShell.Run"cmd /c @echo " & ton, 0
WshShell.Run bin & "\GMDevents.hta",0,True

Set WshShell = Nothing
Set folder = Nothing
Set fso = Nothing
WScript.Quit

Sub Logging(ByRef sMsg)
Dim oFSO, EventMSG, EventTime
EventTime = Now

Set oFSO = CreateObject("Scripting.FileSystemObject")   
Set EventMSG = oFSO.OpenTextFile("F:\GMD\bin\log\Events.log",8,true)

EventMSG.WriteLine"[" & EventTime & "] [FlowControl] [Event: " & sMsg & "]"
EventMSG.Close

Set EventMSG = Nothing
Set oFSO = Nothing
EndSub
```

Leider bleib ich zum einen immer noch an der 7z Syntax hängen und zum anderen hab ich in ZipParts nur ein Datensatz stehen, nähmlich den letzten ("1101 xyz 670.zip")
Wie bekomme ich im aktuellen Fall die "1101 xyz 650.zip", "1101 xyz 660.zip" und "1101 xyz 670 com.zip" auch noch an Bord?

Gruß
amn.ssy


----------



## Zvoni (7. Juni 2014)

Ich verstehe nicht, was du in zeile 27 erreichen willst.

Und zeile 40 kann nie wahr sein


----------



## amn.ssy (7. Juni 2014)

Hallo Zvoni,

in Zeile 27 hole ich mir die Zahl, die am Ende steht, also z.B die 670 von 670.zip
Hinsichtlich der Zeile 40 hast du recht!
Neben der 7z Syntax (evtl. ist Sie sogar schon richtig, da Fehler "kann Datei nicht finden"), liegt mein Problem darin die entsprechenden Zip-Files zusammen zubekommen, die auch zusammen gehören. Im aktuellen Fall sind zwar mehrere Zip's im Ordner, jedoch gehören immer 4 zusammen (die ersten 4 Zeichen sind gleich). Genau diese sollen entpackt werden. 

1101 xyz 650.zip
1101 xyz 660.zip
1101 xyz 670.zip
1101 xyz 670 com.zip

Der Ort wohin ergibt sich aus dem Rest vom Dateinamen.
So sollten die Dateien nach:

\input\raw\xyz 650\
\input\raw\xyz 660\
\input\raw\xyz 670\
\input\com\xyz 670 com\

Dabei existiert bislang nur das Verzeichnisse:

\input\raw\
\input\com\

Die anderen Verzeichnisse wie:

xyz 650 
xyz 660
xyz 670
xyz 670 com 

müßten erstellt werden.

So wie ich das sehe habe ich in ZipParts nur

1101 
xyz 
670.zip

stehen.

Gruß
amn.ssy


----------



## Yaslaw (7. Juni 2014)

Ist mMn eher ein Fall für RegExp (http://msdn.microsoft.com/en-us/library/yab2dx62(v=vs.84).aspx)
Das erstellen der Ordner geht am Einfachsten über das FileSystemObject (also wie du bereits hast)

So grob umrissen:

```
Dim fileName As String
'TODO: Filename setzen
'TODO Ordner Haubtpfad (basisFolderPath) irgendwoher nehmen:
Dim objRegEx: Set objRegExExt= CreateObject("VBScript.RegExp")
Dim objMatches
Dim fso: Set fso = CreateObject("Scripting.Filesystemobject")
Dim folder

'objMatches(0) = Führende Zahl
'objMatches(1) = rest des Namens ohne com
'objMatches(2) = Leer oder com
'objMatches(3) = Dateiendung zip, rar oder 7z

'RegExp Extended. In dem Fall nur für com. Sind da mehrere Spezialordner, dann kann eine Auswahl getroffen werden. zB. anstelle 
'von (com): (com|de|ch)
objRegExExt.Pattern = "^([\d]+) (.+)  (com)\.(zip|rar|7z)$"
If objRegExExt.test(fileName) Then
    'Ist ein Com-Ordner
    Set objMatches = objRegEx.execute(fileName)
    folder = fso.buildPath(basisFolderPath, objMatches(2))  'com hinzufügen
    folder = fso.buildPath(folder , objMatches(1)) 'Rest des Namens hinzufügen
Else
    'RegExp für alle Raw
    objRegEx.Pattern = "^([\d]+) (.+)()\.(zip|rar|7z)$"
    If objRegExExt.test(fileName) Then
        Set objMatches = objRegEx.execute(fileName)
        folder = fso.buildPath(basisFolderPath, "raw")  'raw hinzufügen
        folder = fso.buildPath(folder , objMatches(1)) 'Rest des Namens hinzufügen
    Else
        'TODO: Fehler: Dateiname passt nicht
    End If
End If

If Not fso.folderExist(folder) Then
    fso.createFolder folder
End If

'Todo Zip-File nach folder exportieren
```


----------



## amn.ssy (13. Juni 2014)

Hallo Yaslaw,

da bin ich nochmal mit einer kleinen Erfolgsmeldung.


```
sLw = Left(WScript.ScriptFullName, 2)
    sShDrv = "X:"
    sRoot = sLw & "\gmd"
    sBin = sRoot & "\bin"
    sData = sRoot & "\data"
    sInput = sRoot & "\input"
    sStore = sRoot & "\store"
    sCfg = sBin & "\cfg"
    sExt = sBin & "\ext"
    sLog = sBin & "\log\Events.log"
    sInC = sInput & "\coa"
    sInR = sInput & "\raw"
    sStXLS = sStore & "\xls\"
    sStZip = sStore & "\zip\"
 
'Initialize tools
    s7z = sExt & "\7z.exe"
    'sVbs = sBin & "\getData.exe"
    sVbs = sBin & "\getData.vbs"
    sHta = sBin & "\GMDevents.hta"
 
'Initialize character 34(") for CMDLine
    sQ = Chr(34)
 
'Write message
    Call Logging("start program GMD")
    WScript.Echo ("start program GMD")
 
'Initialize objects and counts
    Set oShell = CreateObject("WScript.Shell")
    Set oFso = CreateObject("Scripting.Filesystemobject")
    iCount = 0
    iFlag = 0
 
'check if shared drive is available
    If (oFSO.DriveExists(sShDrv)) Then
        iFlag = 1
        Call Logging ("shared drive " & sShDrv & " is available!")
    Else
        iFlag = 0
        Call Logging ("shared drive " & sShDrv & " not available!")
    End If
 
 
'Recognize zip files
    For Each oFile In oFso.GetFolder(sData).Files
        If LCase(oFso.GetExtensionName(oFile.Name)) = "zip" Then
            aZipParts = Split(oFso.GetBaseName(oFile.Path), " ", 2)
 
'Recognize coa and create folders
            If InStr(1, oFile.Name, "coa", vbTextCompare) > 0 Then
                sFolderOut = sQ & oFso.BuildPath(sInC, aZipParts(1)) & sQ
            Else
                sFolderOut = sQ & oFso.BuildPath(sInR, aZipParts(1)) & sQ
            End If
 
'Write message
            Call Logging("extract " & aZipParts(1) & " data from " & aZipParts(0))
 
'Extract zip files to created folders
            CmdLine = sQ & s7z & sQ & " e " & sQ & oFile.Path & sQ & " -y -o" & sFolderOut
            oShell.Run CmdLine, 0, True:  iCount = iCount + 1
        End If
        
'Write message
    Call Logging ("move " & oFile.Path & " to " & sStZip)
    
'move Zip file to \store\zip
    oFso.CopyFile oFile.Path, sStZip, true
    oFso.DeleteFile oFile.Path
            
    Next
 
'Initialize data search and export program
    If iCount = 0 Then
        'Write message
        Call Logging("zip file(s) not available")
    Else
        With oShell
            'Write message
            Call Logging("search\export data to final XLSX file(s)")
 
'Search for data and export to final XLSX files
            For Each sName In Array("xyz 400", "xyz 600", "xyz 800")
            
            sMonth = Right(aZipParts(0),2)
            sMonthEN = getMonth(MonthName(sMonth,True))
            sYear = Left (aZipParts(0),2)
            sProdName = Split(sName," ")
            sProduct = sProdName(0)
 
            Select Case Right(sProdName(1),3)
            Case 400
                sLN = "a278"
            Case 600
                sLN = "a280"
            Case 800
                sLN = "b950"
            Case Else
                Call Logging("assignment to LN not possible!")
            End Select
            sFullProdName = sProduct & " " & sLN
                
                CmdLine = sQ & sVbs & sQ & " " & sQ & oFso.BuildPath(sCfg, sName & ".ini") & sQ
                .Run CmdLine, 0, True
 
                If iFlag = 1 Then
 
'Write message
                    Call Logging ("move " & sName & ".xlsx" & " to Product data path")
 
'move Result xlsx file to Product data path                 
                    oFSO.CopyFile sStXLS & sName & ".xlsx", _
                    "X:\groups\RnS_TM\00 DnA\03-" & sYear & " Monthly\TPM\" & sFullProdName & "\" & sMonth & " - " & sMonthEN & "\Data\", True
                    oFSO.DeleteFile sStXLS & sName & ".xlsx"
 
'Write message
                    Call Logging ("move " & sName & ".zip" & " to Product data path")
 
'move Result xlsx file to Product data path             
                    oFSO.CopyFile sStZip & sYear & sMonth & " " & sName & "*.zip", _
                    "X:\groups\RnS_TM\00 DnA\03-" & sYear & " Monthly\TPM\" & sFullProdName & "\" & sMonth & " - " & sMonthEN & "\Data\Zip\", True
                    oFSO.DeleteFile sStZip & sYear & sMonth & " " & sName & "*.zip"
                End If
            Next
 
'Write message
    Call Logging("end program GMD")
    WScript.Echo ("end program GMD")
 
'Signal end of program and show log file
                .Run "cmd /c @echo " & Chr(7), 0, False
                .Run sQ & sHta & sQ, 0, False
        End With
    End If
 
'Deallocate objects and exit program
    Set oFso = Nothing
    Set oShell = Nothing
    WScript.Quit
 
'Function to convert MonthName from GER to EN
Function getMonth(sMonthEN)
    Select Case sMonthEN
    Case "Mrz"
        getMonth = "Mar"
    Case "Mai"
        getMonth = "May"    
    Case "Okt"
        getMonth = "Oct"
    Case "Dez"
        getMonth = "Dec"
    Case Else
        getMonth = sMonthEN
    End Select
End Function
 
'Function to create and write log-file
Function Logging(ByRef sMsg)
    Dim oFSO, EventMSG
    Set oFSO = CreateObject("Scripting.FileSystemObject")
    Set EventMSG = oFSO.OpenTextFile(sLog,8,true)
    EventMSG.WriteLine "[" & Now & "] [FlowControl] [Event: " & sMsg & "]"
    EventMSG.Close
    Set EventMSG = Nothing
End Function
```
 
Möglicherweise mache ich da ein paar Sachen über die Brust ins Auge, aber bis dahein funktioniert das ganze ohne Problem 

Nun würde ich dem ganzen noch gerne die Krone aufsetzen und den kompletten ablauf in eine Do - Loop Schleife setzen.
Aktuell funktioniert das wenn ich X Zip-Dateien im Ordner \Data habe die alle mit den gleichen Zeichen beginnen (z.B. 4 Zips beginnend mit 1310).
Danach folgen weitere Zeichen, die sind für die Loops aber nicht entscheidend.
In diesem Fall gehören die 4 Dateien zu einem Prozess. Die 13 steht für YY, die 10 für MM.
Nun möchte ich idealerweise im Data-Ordner auch gleich (soweit vorhanden) 1311, 1312, 1401, 1402, usw. ablegen können.
Aktuell werden alle Zip-Dateien verarbeitet die erfindet. Das würde ziemliches Chaos geben - ich benötige zwingend eine Trennung.
Wie kann man dem Script beibringen, das es solange immer wieder neu durchlaufen werden soll wie Zip-Dateien im Ordner sind, diese jedoch in Gruppen abgearbeitet werden müssen (erst alle 1310 - Loop - dann alle 1311 - Loop - usw.)?

LG
amn.ssy


----------

