Avatar billede madsnor Nybegynder
15. september 2003 - 09:44 Der er 30 kommentarer og
1 løsning

Import output fra batch-script

Jeg ønsker at kalde et batch-script med 2 argumenter - output'et fra batchscriptet skal ind i cellen ligesom en formel, blot er data fra en ekstern udført funktion.

Kan man bruge VBA til dette: kald ekstern batch-fil med argumenter (evt. pipe output til en fil) + importér fil når batchscript er færdig?
Avatar billede aheiss Praktikant
15. september 2003 - 09:51 #1
Du kan kalde et batch script med følgende kommande
Sub batchkorsel()
Dim RetVal
RetVal = Shell("C:\temp\batfil.bat")
End Sub
______________________
Men hvis du ønske at skrive til bat filen kræver det en gendannelse, mener jeg. Så vil du det ? Og hvilket data leverer bat filen ?
Avatar billede stefanfuglsang Juniormester
15. september 2003 - 10:07 #2
Ovenstående kører en batch-fil, men henter ikke output.
Du kan dirigere output til en txt-file og lave en vba-procedure til at læse værdien/erne:
Hvis der kun er én værdi, så skal der ikke bruges array og do-while i nedenstående

Sub ReadValues()
    Dim numbers(100) As Double
    Open "C:\stitilfil\outfile.txt" For Input As #1
    Do While Not EOF(1)
        Input #1, numbers(i)
        i = i + 1
    Loop
    Close #1
End Sub

OBS: du kan ikke være sikker på at batch-filen er færdig, hvis du kører ReadValues umiddelbart efter batch-jobbet - du skal nok teste på om du kan åbne txt-filen, inden du læser indholdet (f.eks. med "On error goto filenotready" lige før Open ...).
Avatar billede madsnor Nybegynder
15. september 2003 - 10:11 #3
Jeg har lavet et batch-script som tager 2 argumenter: hostnavn og drevbogstav.
Scriptet returnerer antallet af bytes brugt på det pågældende drev på host'en.

Det er lavet som batch-script da vbscript med WMI ikke fungerede på alle servere (gl. NT4 uden WMI-core).

Tænkt eksempel:
kald "batfil.bat win01 c"
returnerer "123123132" (uden anførselstegn)
Avatar billede madsnor Nybegynder
15. september 2003 - 10:15 #4
Jeg vil selvfølgelig gerne lave en host/drevbogstav liste i excel og i cellen ved siden af skal der så står hvor meget diskplads der er brugt.
Avatar billede aheiss Praktikant
15. september 2003 - 10:39 #5
Nedenstående kode kunne være første skridt. Den laver bat filen og kører den. Du må selv justere til så den referer til celler i dit ark, men det skulle ikke være noget problem. Når du har fået det til at køre, kan vi kigge på data load, med mindre stefanfuglsangs kode bare kører. :

Sub koersel()
Module1.lav_bat
Module1.omdoeb
Module1.batchkorsel
End Sub
Sub lav_bat()
Dim batfil As String, sti As String
sti = "C:\temp\"
batfil = "C:\temp\batfil"
If Dir(batfil, vbNormal) = "" Then
    Workbooks.Add
    Module1.indsætbat_tekst
        ChDir sti
        ActiveWorkbook.SaveAs Filename:=batfil & ".txt", FileFormat:=xlText
    ActiveWorkbook.Close (False)
    Else
    Kill batfil
    Workbooks.Add
    Module1.indsætbat_tekst
        ChDir sti
        ActiveWorkbook.SaveAs Filename:=batfil & ".txt", FileFormat:=xlText
    ActiveWorkbook.Close (False)
End If
End Sub
Sub indsætbat_tekst()
[a1] = "Batch File(batfil.bat)"
[a2] = "@echo off"
[a3] = "cls"
End Sub
Sub omdoeb()
        FileCopy "c:\temp\batfil.txt", "c:\temp\batfil.bat"
        Kill "c:\temp\batfil.txt"
End Sub
Sub batchkorsel()
Dim RetVal
RetVal = Shell("C:\temp\batfil.bat")
End Sub
Avatar billede madsnor Nybegynder
15. september 2003 - 11:43 #6
Jeg er ikke nogen haj til excel, så hvorledes får jeg RetVal ind i en celle?
Jeg har prøvet at tilføje en linie i indsætbat_tekst()
[a4]= echo 1
og en linie i batchkorsel():
[b1] = RetVal
men det giver nye resultater i celle b1 for hver kørsel.
Hvorledes skrives resultatet til en celle?
Hvorledes kan jeg brygge en batfil sammen på ovenstående måde, men hvor der inkluderes data fra andre celler, fx. ("lidt generic")
[a4] = "echo " + [b4] + " " + [c4]
Avatar billede aheiss Praktikant
15. september 2003 - 12:07 #7
Giv lige et eksempel på de to linjer fra din batfil.
Avatar billede madsnor Nybegynder
15. september 2003 - 13:21 #8
Her er et eksemplet fra den "rigtige" batfil - %%1 og %%2 skal udskiftes med hhv hostnavn & drevbogstav:
FOR /F "tokens=3* delims= " %%? IN ('DIR /-c \\%1\%2$ 2^>NUL ^| FIND "bytes free"') DO SET free=%%?

Ændringer til ovenstående macro:
Sub indsætbat_tekst()
[a1] = "@echo off"
[a2] = "cls"
[a3] = "echo 1"
End Sub

Sub batchkorsel()
Dim RetVal
RetVal = Shell("C:\temp\batfil.bat")
[b1] = RetVal
End Sub
Avatar billede aheiss Praktikant
15. september 2003 - 13:49 #9
Jeg er nok lidt langsom, men lige for at være helt sikker. Din bat fil har to linjer, hvor den første eksempelvis ser således ud :
linje 1 :
FOR /F "tokens=3* delims= " %% IN ('DIR /-c \\win01\c$ 2^>NUL ^| FIND "bytes free"') DO SET free=%%?
(hvor win01 og c skal hentes fra arket)
(skal %% også erstattes ? )


Linje 2 : har jeg ikke helt forstået.
Eksemplet jeg gav på batch filen glemmer vi.

[b1]= RetVal duer ikke, men hvorledes leverer batchkørslen sine data. En txt fil eller ?
Avatar billede madsnor Nybegynder
15. september 2003 - 14:04 #10
jeg udtrykker mig nok ikke klart nok. %%? skal ikke skiftes - det er en del af FOR mekanismen.
FOR linien tygger ('DIR...) kommandoen igennem og tildeler environment variablen FREE en værdi, nogenlunde det samme gør næste linie i scritet, blot finder den hvor stor disken er i variablen SIZE.
SIZE og FREE subtraheres og jeg har så hvor meget diskplads der er brugt - DET kan enten læses ud (med ECHO) på consollen eller til en fil.
Hvor det ryger hen er underordnet blot Excel kan få tallet ind.
Jeg vil gerne kalde scriptet med "win01" og "c", eller generere en ny batfil (for hver kørsel) med dataene i, men dataene skal komme fra excel-arket, og resultatet placeres ved siden af dataene.
Avatar billede bak Forsker
15. september 2003 - 14:17 #11
Hvis du har lavet bat-filer allerede og den kun returnerer een linie, burde følgende kunne bruges både som indbygget function og regnearkfunction

Function test(stHost As String, stDrive As String)
Dim ifreefil As Long
Dim textline As String
'find størrelsen og overfør til tekstfil
Shell "c:\getdrive.bat " & stHost & " " & stDrive & " > c:\getdrive.txt"
ifreefil = FreeFile
'Åbn tekstfilen og hent størrelse
Open "c:\getdrive.txt" For Input As #ifreefil
    Line Input #ifreefil, textline
Close #ifreefil
test = textline
End Function
Avatar billede bak Forsker
15. september 2003 - 14:23 #12
Der kan være et delay ved shell kommandoen og filen getdrive.txt bør måske angiver i funktionens parametre, men med een fil kan jeg godt få det til at virke. Shell kører din bat-fil med parametre og piper den til tekstfil.
Avatar billede madsnor Nybegynder
15. september 2003 - 14:26 #13
Hvorledes indtaster jeg den? I macroeditoren (alt-f11)?
Avatar billede bak Forsker
15. september 2003 - 15:21 #14
Jeg har lige lavet den lidt om og indsat 1 sek. delay, samt en streng til filnavn. Du trykker bare alt-f11 og indsætter den i et modul.
Sub test3 er bare et eksempel

Function test(stHost As String, stDrive As String, stFName As String)
Dim ifreefil As Long, newHour As Long, newMinute As Long, newSecond As Long, waitTime As Long
Dim textline As String
Shell "c:\Getdrive.bat " & stDrive & " > " & stFName
newHour = Hour(Now())
newMinute = Minute(Now())
newSecond = Second(Now()) + 2
waitTime = TimeSerial(newHour, newMinute, newSecond)
Application.Wait waitTime
ifreefil = FreeFile
Open stFName For Input As #ifreefil
    Line Input #ifreefil, textline
Close #ifreefil
test = textline
End Function

Sub test3()
Dim drive As String
Dim host As String
host = "applsrv1"
drive = "H"
MsgBox test(host, drive, "c:\getdrive.txt")

End Sub
Avatar billede bak Forsker
15. september 2003 - 15:27 #15
du skal lige ændre linie 4 til
Shell "c:\getdrive.bat " & stHost & " " & stDrive & " > " & stFName

(jeg testede kun med een parameter)
Avatar billede madsnor Nybegynder
16. september 2003 - 15:36 #16
Det tog lidt tid før jeg fattede at funktionen "test" kun kunne kaldes fra en macro (og ikke indtastes som formel i en celle, som fx
=test(A1, B1, "c:\getdrive.txt")
jeg ændrede følgende i test3()
host = [a1]
drive = [b1]
[c1] = test(host, drive, "c:\getdrive.txt")

Og det virker!

Der er dog et men: wait delen fungerer IKKE, (selv jeg prøver at tilføje +1 til minut-delen), så optimalt ville være hvis man kunne slette "getdrive.txt" filen først, og i funktionen "test" teste for om filen "getdrive.txt" findes. Hvis ikke: loope nogle gange for at vente på den, og når den så dukker op køre videre som det er nu, (og springe ud af loop hvis det tager for lang tid før filen kommer).

Derudover ville det være smart i test3() at lave en løkke der laver et index 1..x og så tager argumenter til funktionen test i arket, fx test(a1, b1, "...") + skriver resultatet i c1, dernæst test(a2, b2, "...") + resultatet i c2 etc. etc.
Avatar billede aheiss Praktikant
17. september 2003 - 10:01 #17
Denne her skulle komme tæt på tror jeg :

Sub test3()
getfil = "c:\getdrive.txt"
If Dir(getfil, vbNormal) <> "" Then
    Kill "c:\getdrive.txt"
End If
For a = 1 To 60000
If Cells(a, 1) = "" Then
    Exit Sub
End If
Dim drive As String
Dim host As String
Dim data As Long
    host = Cells(a, 1)
    drive = Cells(a, 2)
    data = test(host, drive, "c:\getdrive.txt")
    taller = 1
omigen:
    If Dir(getfil, vbNormal) = "" Then
    taller = taller + 1
        If taller = 1000 Then
        MsgBox ("Tiden er udløbet for" & Cells(a, 1) & Cells(1, 2))
        Exit Sub
        Else
        GoTo omigen
        End If
    Else
        Cells(a, 3) = data
    End If
Next
End Sub
Avatar billede aheiss Praktikant
17. september 2003 - 11:14 #18
Jeg overså lige et par ting! Denne her er bedre  :
_________________________________________
Sub test3()
getfil = "c:\getdrive.txt"
For a = 1 To 60000
If Dir(getfil, vbNormal) <> "" Then
    Kill getfil
End If
If Cells(a, 1) = "" Then
    Exit Sub
End If
Dim drive As String
Dim host As String
Dim data As Long
    host = Cells(a, 1)
    drive = Cells(a, 2)
    data = test(host, drive, "c:\getdrive.txt")
    taller = 1
omigen:
    If Dir(getfil, vbNormal) = "" Then
    taller = taller + 1
        If taller = 3000 Then
        Cells(a, 3) = "Tid udløbet"
        GoTo fortsæt
        Else
        GoTo omigen
        End If
    Else
        Cells(a, 3) = data
    End If
fortsæt:
Next
End Sub
Avatar billede madsnor Nybegynder
17. september 2003 - 12:54 #19
Jeg får en "Run-time error '6': Overflow" i linien
data = test(host, drive, "c:\getdrive.txt") (under debug med F8)
lige når funktionen 'test' returnerer resultat til test3()
Kan det være fordi 'textline' er string og 'data' er long?
Avatar billede aheiss Praktikant
17. september 2003 - 13:35 #20
Ja prøv at slette
Dim data As Long eller sæt ' foran
Avatar billede aheiss Praktikant
17. september 2003 - 13:39 #21
Kan jeg køre din batfil? Hvis ja kan du så ikke sende den til ah6@sol.dk
Så kan jeg da eksperimentere lidt. Og så vil jeg da i det hele taget gerne se hvordan sådan en fætter virker.
Avatar billede aheiss Praktikant
17. september 2003 - 14:56 #22
OK - den er lidt svær idet min batfil ikke rigtigt leverer noget brugbart. Jeg havde ihvertfald overset at det er i funktionen der skal ventes - ikke i subben. Hvad sker der med denne her (både Function og Sub):

Function test(stHost As String, stDrive As String, stFName As String)
Dim ifreefil As Long, textline As String
mappe = "c:\"
getfil = mappe & "getdrive.txt"
batfil = mappe & "getdrive.bat"
Shell batfil & " " & stHost & " " & stDrive & " > " & stFName
    taller = 1
omigen:
    If Dir(getfil, vbNormal) = "" Then
    taller = taller + 1
        If taller = 3000 Then
        Exit Function
        Else
        GoTo omigen
        End If
    Else
        ifreefil = FreeFile
        Open stFName For Input As #ifreefil
            Line Input #ifreefil, textline
        Close #ifreefil
        test = textline
    End If
End Function
Sub test3()
Dim getfil As String
getfil = "c:\getdrive.txt"
For a = 1 To 60000
If Dir(getfil, vbNormal) <> "" Then
    Kill getfil
End If
If Cells(a, 1) = "" Then
    Exit Sub
End If
Dim drive As String
Dim host As String
    host = Cells(a, 1)
    drive = Cells(a, 2)
    data = test(host, drive, getfil)
    Cells(a, 3) = data
Next
End Sub
Avatar billede madsnor Nybegynder
17. september 2003 - 15:44 #23
Jeg har mailet batfilen til dig.
Den tager relativt lang tid om at køre, hvilket resulterer nogle gange i at tælleren når forbi de 3000 og så er løbet kørt for det drev.
Andre gang kolliderer macroen med batfilen, idet jeg får en access denied - formodentlig er filen lige ved at blive skrevet!

Det bedste ville være at vente en given maksimum tid fx 10 sek. og i det tidsrum checke hvert sekund om filen er der. Hvis den er, kan den forsøges åbnet, men der skal være en 'on error goto' funktion således at filen forsøges åbnet flere gange (gerne med et sekunds pause).
Avatar billede madsnor Nybegynder
17. september 2003 - 15:48 #24
application.wait virker nu - (virkede ikke i min office 2003 beta)
Avatar billede aheiss Praktikant
17. september 2003 - 16:05 #25
OK - så bruger jeg den (den virker godt nok ikke hos mig - desværre)
Avatar billede aheiss Praktikant
17. september 2003 - 16:17 #26
bat filen kører ikke rigtigt - men wait virker alligevel : Prøv :

Function test(stHost As String, stDrive As String, stFName As String)
Dim ifreefil As Long, textline As String
mappe = "c:\"
getfil = mappe & "getdrive.txt"
batfil = mappe & "getdrive.bat"
Shell batfil & " " & stHost & " " & stDrive & " > " & stFName
taller = 1
omigen:
    newHour = Hour(Now())
    newMinute = Minute(Now())
    newSecond = Second(Now()) + 1
    waitTime = TimeSerial(newHour, newMinute, newSecond)
    Application.Wait waitTime
    If taller = 10 Then        ' max ventetid
        test = "timeout"
        Exit Function
    End If
    If Dir(getfil, vbNormal) = "" Then
        taller = taller + 1
    GoTo omigen
    Else
    On Error GoTo omigen
        ifreefil = FreeFile
        Open stFName For Input As #ifreefil
            Line Input #ifreefil, textline
        Close #ifreefil
        test = textline
    End If
End Function
Sub test3()
Dim getfil As String
getfil = "c:\getdrive.txt"
For a = 1 To 60000
If Dir(getfil, vbNormal) <> "" Then
    Kill getfil
End If
If Cells(a, 1) = "" Then
    Exit Sub
End If
Dim drive As String
Dim host As String
    host = Cells(a, 1)
    drive = Cells(a, 2)
    data = test(host, drive, getfil)
    Cells(a, 3) = data
Next
End Sub
Avatar billede bak Forsker
17. september 2003 - 16:36 #27
kunne jeg ikke lige se et eksempel på hvordan du skriver  host og drive.
drive gætter jeg på du skrive således "G:\" men.....
Avatar billede bak Forsker
17. september 2003 - 16:37 #28
og hvad er iøvrig VMI ?
Avatar billede madsnor Nybegynder
18. september 2003 - 08:14 #29
Hov - kom til at klikke afvis.
Aheiss, du får 120 point for super hjælp i denne sag (skal lige finde ud af hvorledes jeg får dem overført til dig).

Macro/funktionerne virker fint nu (der skulle lige tweakes lidt med timeout - nogle hosts er længe om at svare)

Jeg har lavet arket således at i [a1] er der en tæller der læses/opdateres af macroen. Tælleren angiver hvilken kolonne der skal fyldes tal i, dvs. jeg kan få en historik over diskforbrug på en række servere og lave grafer derover.

Jeg forsøgte mig lidt med 'date' og 'time' funktionerne, men kunne ikke få et brugbart resultat i een celle (nu bruger jeg 'now'), men ville gerne have et eksempel på hvorledes jeg kan få dato/tid i eet felt (OG lave beregninger på feltet (fx antal dage mellem datoerne)).

Er der en smart måde i macro at generere en 'scatter chart'?
Jeg har data i rækkerne, med legend i a & b (hostnavn, drive), X-data i række 1. (datoen for kørslen) og Y-data i c,d,e,f...., samt en tæller der viser hvor langt cellerne er fyldt ud med data.

Angående WMI spørgsmålet - det betyder Windows Management Instrumentation, og er en kilde/metode til at trække alle mulige former for data ud af Windows og ikke mindst konfigurere og administrere windows fra scripts.
http://www.microsoft.com/technet/treeview/default.asp?url=/technet/prodtechnol/windowsserver2003/proddocs/standard/ref_prog_winwmiref.asp
http://techsupt.windowware.com/TS/T000001002F1.html

Her er koden som den endte op med:

Function GetDSU(stHost As String, stDrive As String, stFName As String)
Dim ifreefil As Long, textline As String
mappe = "c:\temp\"
getfil = mappe & "fil2.txt"
batfil = "c:\temp\dsu_excel.bat"
Shell batfil & " " & stHost & " " & stDrive & " > " & stFName
taller = 1
omigen:
    newHour = Hour(Now())
    newMinute = Minute(Now())
    newSecond = Second(Now()) + 1
    waitTime = TimeSerial(newHour, newMinute, newSecond)
    Application.Wait waitTime
    If taller = 20 Then        ' max ventetid
        GetDSU = "timeout"
        Exit Function
    End If
    If Dir(getfil, vbNormal) = "" Then
        taller = taller + 1
    GoTo omigen
    Else
    On Error GoTo omigen
        ifreefil = FreeFile
        Open stFName For Input As #ifreefil
            Line Input #ifreefil, textline
        Close #ifreefil
        GetDSU = textline
    End If
End Function
Sub dsu()
Dim getfil As String, ColumnOffset As Long
getfil = "c:\temp\fil2.txt"
ColumnOffset = Cells(1, 1)
Cells(1, 1) = ColumnOffset + 1
Cells(1, ColumnOffset) = Now
For a = 2 To 60000
If Dir(getfil, vbNormal) <> "" Then
    On Error Resume Next
    Kill getfil
End If
If Cells(a, 1) = "" Then
    Exit Sub
End If
Dim drive As String
Dim host As String
    host = Cells(a, 1)
    drive = Cells(a, 2)
    data = GetDSU(host, drive, getfil)
    Cells(a, ColumnOffset) = data
Next
End Sub
Avatar billede aheiss Praktikant
18. september 2003 - 11:43 #30
Points giver man ved at acceptere et svar, så her er et svar. Du kan i øvrigt fordele points til andre svarere!

Mht. Dato format er jeg ikke helt klar over problematikken. Men hvis du trækker to datoer fra hinanden, får du antal dage, hvis denne nye celle er formateret som tal.

Makro til at lave en graf.  Håber at følgende kode bringer dig videre. Den laver som eksempel en graf med data fra række 3. Koden er ikke dynamisk på nogen måde, men det klarer du jo fint selv kan jeg se :-)

Sub graf()
Dim overskrift As String
    overskrift = Sheets("Ark1").Range("a3") & Sheets("Ark1").Range("b3")
With Charts.Add
End With
    ActiveChart.ChartType = xlXYScatter
    ActiveChart.SeriesCollection.NewSeries
    ActiveChart.SeriesCollection(1).XValues = Sheets("Ark1").Range("c1:h1")
    ActiveChart.SeriesCollection(1).Values = Sheets("Ark1").Range("c3:h3")
    ActiveChart.Location Where:=xlLocationAsObject, Name:="Ark1"
    ActiveChart.Legend.Delete
End Sub
Avatar billede aheiss Praktikant
18. september 2003 - 12:49 #31
Svar ? Dette er et svar =)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Vi har et stort udvalg af Excel kurser. Find lige det kursus der passer dig lige her.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester