I figure that I could post this as a unique way of returning output as text instead of integers to see if this can help others that are having the same issue as I am having.
What I'm trying to accomplish is holding the output of the command, but then channeling a specific output out as a text instead of being interger based.
Here's what I have so far, and I'm currently stuck on filtering the output. I know that I can use the mid command, but since the output in general from this command is fluid, I can't use mid to count specific characters.
The command in question is PowerShell.exe manage-bde -status C:
The output is this:
Volume C: [OSDisk]
[OS Volume]
Size: 118.24 GB
BitLocker Version: Windows 7
Conversion Status: Fully Encrypted
Percentage Encrypted: 100%
Encryption Method: AES 256
Protection Status: Protection On
Lock Status: Unlocked
Identification Field: None
Key Protectors:
Numerical Password
TPM
I need to pull some information from say for instance Conversion Status. I want it to tell me if it's 100%, or 0%...or whatever it is. I can't seem to pull just that line.
Here's what I have so far.
dim outputArray
dim inputText
dim message
Dim strText
Set objShell = WScript.CreateObject("WScript.Shell")
Set objExecObject = ObjShell.Exec("PowerShell.exe manage-bde"" -status C:")
Do While Not objExecObject.StdOut.AtEndOfStream
strText = objExecObject.StdOut.ReadLine()
inputText = strText
outputArray = split(inputText,"Converstion Status:")
for each x in outputArray
message = message & x & vbCRLF
next
msgbox message
Loop
This does a line by line pull, and I know that Conversion Status is the 3rd line, so maybe something to that effect of channeling that line and echoing the 100% to a variable that I can store as a separate output.
Update: I decided not to go through the approach of parsing the output to a text file. There has to be a better way and shorter code to accomplish this methodology, plus if Bitlocker variables get changed around on the output, my line methodology might not work.
I'm now trying to see if I can use the for /F search approach to find the string and set the variable. The goal for me to do all of this is to add it to a registry key that will contain these values for reporting
Here's my revised code.
dim outputArray
dim inputText
dim message
Dim strText
dim line
dim testCase
dim strConversion
dim Currentline
Set objShell = WScript.CreateObject("WScript.Shell")
Set objExecObject = ObjShell.Exec("PowerShell.exe manage-bde"" -status C:")
Do While Not objExecObject.StdOut.AtEndOfStream
strText = objExecObject.StdOut.ReadLine()
strConversion = "for /F ""delims="" %%a in (strText) do do findstr /M /i /C:'Conversion' C:\%i var=%%a"
Wscript.echo strConversion
Loop
This does a line by line pull, and I know that Conversion Status is the 3rd line, so maybe something to that effect of channeling that line and echoing the 100% to a variable that I can store as a separate output.
Update: I decided not to go through the approach of parsing the output to a text file. There has to be a better way and shorter code to accomplish this methodology, plus if Bitlocker variables get changed around on the output, my line methodology might not work.
I'm now trying to see if I can use the for /F search approach to find the string and set the variable. The goal for me to do all of this is to add it to a registry key that will contain these values for reporting.
Here's my revised code.
dim outputArray
dim inputText
dim message
Dim strText
dim line
dim testCase
dim strConversion
dim Currentline
Set objShell = WScript.CreateObject("WScript.Shell")
Set objExecObject = ObjShell.Exec("PowerShell.exe manage-bde"" -status C:")
Do While Not objExecObject.StdOut.AtEndOfStream
strText = objExecObject.StdOut.ReadLine()
strConversion = "for /F ""delims="" %%a in (strText) do findstr /M /i /C:'Conversion' C:\%i var=%%a"
Wscript.echo strConversion
Loop
So far when running it, it parrots back the line back 14 times which is the number of lines when you run the command straight. So, it is seeing it, just not fully parsing the data. "Conversion" is one the strings that I'm having it check for.
Another reason I don't want to do longer code is this is part of a script that already has quite a few lines, and this will be a final sub process.
Try to store the output into array like this code :
Option Explicit
Dim arrData,Data
If Not WScript.Arguments.Named.Exists("elevate") Then
CreateObject("Shell.Application").ShellExecute WScript.FullName _
,WScript.ScriptFullName & " /elevate", "", "runas", 1
WScript.Quit
End If
arrData = Run_PS_Script
MsgBox arrData(6)
'To get all data from this loop For...Next
For Each Data in arrData
MsgBox Data
Next
'*****************************************************************
Function Run_PS_Script()
Dim WshShell,Command,PSFile,ret,fso,file,text,Temp
Set WshShell = CreateObject("WScript.Shell")
Temp = WshShell.ExpandEnvironmentStrings("%Temp%")
Command = "cmd /c echo manage-bde -status C: ^|" &_
"Out-File %temp%\output.txt -Encoding ascii > %temp%\PSFile.ps1"
PSFile = WshShell.Run(Command,0,True)
ret = WshShell.Run("powershell.exe -ExecutionPolicy Unrestricted -File %temp%\PSFile.ps1",0,True)
Set fso = CreateObject("Scripting.FileSystemObject")
text = ReadFile(Temp &"\output.txt","byline")
Run_PS_Script=text
End Function
'*****************************************************************
Function ReadFile(path,mode)
Const ForReading = 1
Const TriStateUseDefault = -2
Dim objFSO,objFile,i,contents,strLine
Set objFSO = CreateObject("Scripting.FileSystemObject")
If mode = "unicode" Then
Set objFile = objFSO.opentextfile(path,,,true)
contents = objFile.ReadAll
ReadFile = contents
objFile.Close
End If
If mode = "byline" then
Set objFile = objFSO.OpenTextFile(path,ForReading)
Dim arrFileLines()
i = 0
Do Until objFile.AtEndOfStream
Redim Preserve arrFileLines(i)
strLine = objFile.ReadLine
strLine = Trim(strLine)
If Len(strLine) > 0 Then
arrFileLines(i) = strLine
i = i + 1
ReadFile = arrFileLines
End If
Loop
objFile.Close
End If
If mode = "all" Then
Set objFile = objFSO.OpenTextFile(path,ForReading)
contents = objFile.ReadAll
ReadFile = contents
objFile.Close
End If
End Function
'*****************************************************************
Okay, I want to post another variation again. How about this?
dim outputArray
dim inputText
dim message
Dim strText
Dim MyArray
conversion = "Conversion Status:"
Set objShell = WScript.CreateObject("WScript.Shell")
Set objExecObject = ObjShell.Exec("PowerShell.exe manage-bde"" -status C:")
Do While Not objExecObject.StdOut.AtEndOfStream
strText = objExecObject.StdOut.ReadLine()
inputText = strText
outputArray = split(inputText,"Conversion Status:")
for each i in outputArray
output = i
next
position = InStr(1, strText,conversion, 1)
msgbox position
Loop
I've got it now where it will return the 0 or 5 value for the line. How can I convert the 5 response back to actual text that came from that line?
Here is an example of pulling values from an array of strings in VBS:
' let us mock out our expected data returned from the disk
Dim sampleData(100)
sampleData(0) = "Volume C: [OSDisk]"
sampleData(1) = "[OS Volume]"
sampleData(2) = ""
sampleData(3) = " Size: 118.24 GB"
sampleData(4) = " BitLocker Version: Windows 7"
sampleData(5) = " Conversion Status: Fully Encrypted"
sampleData(6) = " Percentage Encrypted: 100%"
sampleData(7) = " Encryption Method: AES 256"
sampleData(8) = " Protection Status: Protection On"
sampleData(9) = " Lock Status: Unlocked"
sampleData(10) = " Identification Field: None"
sampleData(11) = " Key Protectors:"
sampleData(12) = " Numerical Password"
sampleData(13) = " TPM"
'create a function to parse out the values you want
Function returnValueFromData(sampleData,fieldName)
For each infoLine in sampleData
If InStr(infoline,fieldName) Then
infoline = Trim(Replace(infoline,fieldName,""))
returnValueFromData = infoline
End If
Next
End Function
'now, we can use our function above to grab whatever field we want
'get the size of the disk
dim size
size = returnValueFromData(sampleData,"Size:")
wscript.echo size
'get the lock status of the disk
dim lockStatus
lockStatus = returnValueFromData(sampleData,"Lock Status:")
wscript.echo lockStatus
'shorthand to get the encryption algorithm
wscript.echo returnValueFromData(sampleData,"Encryption Method:")
Related
Below is the example data availble in txt file
I want to extract the data in another txt file which Sr no is 1.
Please suggest me the VBA code which execute CMD command and bifurcate the data in another txt file.I have search the internet and got to know it is possible via use Shell(" "). help me to achieve my above object.
My txt file(i.e. file3) is available in Z:\ drive.
via below code i can open the cmd command window
Sub macro()
Call Shell("cmd.exe", vbNormalFocus)
End Sub
The Call Shell(,) command is what loads CMD.
If you want to load a file from the CMD, through VBA, you would use something such as:
Sub Open_CPT()
Dim Loc As String
Loc = "Z:/#CPT.bat"
Call Shell(Loc, 1)
End Sub
This will open the file or item at that location.
Depending how you want to bifurcate/split your data, you might want to use the native function of Excel/VBA to open the file and delimit by spaces/tabs/etc. You can then save as a .txt file, after modifications have been made how you want.
Thanks for your guidance as per the instructions of Dave I have developed the below code with the help of FileSystemObject
Please find the below solution.
Sub VBA()
Dim fr, t As String
Dim s As String
ReDim arr(500) As String
ReDim arri(500) As String
Dim i As Long
i = 0
ii = 0
Dim n As Integer
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")
fr = "z:\file3.txt"
Set oFS = fso.OpenTextFile(fr)
Do While Not oFS.AtEndOfStream
arr(i) = oFS.ReadLine
sls = InStr(1, arr(i), 1, vbTextCompare)
If sls >= 1 Then
arri(ii) = arr(i)
ii = ii + 1
End If
i = i + 1
Loop
oFS.Close
n = FreeFile()
s = arri(0)
For ix = LBound(arri) + 1 To UBound(arri)
s = s & vbCrLf & arri(ix)
Next
Open "z:\file2.txt" For Output As #n
Print #n, s
End Sub
I need to create a function in Excel that allows me to read a value form one cell that contains the name of an Active Directory Group and obtain the members of that group and load that information in another cell.
I use something like this to run my Ruby scripts from Excel.
Create a button and edit the macro behind it.
Replace the command and script executed with the one you need for your AD search.
The example takes the value of cell A2 and uses it as input in the script to produce the output in cell D2.
Sub Knop1_Klikken()
Dim objShell As Object
Dim objWshScriptExec As Object
Dim objStdOut As Object
Dim rline As String
Dim strline As String
Dim arg As String
Dim command As String
arg = Worksheets("Blad1").Range("A2")
Set objShell = CreateObject("WScript.Shell")
command = "cmd.exe /S /C ruby ""C:\Users\Gebruiker\ruby\excel\run.rb"" " & arg
Set objWshScriptExec = objShell.Exec(command)
Set objStdOut = objWshScriptExec.StdOut
While Not objStdOut.AtEndOfStream
rline = objStdOut.ReadLine
If rline <> "" Then strline = strline & vbCrLf & rline
Wend
Worksheets("Blad1").Range("D2") = strline
End Sub
I have to do the following:
Open mail -> Check Subject -> If subject is not like : ..... cID#[4digit] -> Add a cID#[4digit] to it, based on other mail's subjects in your folders and sub-folders -> other operations.
Basically check for the highest value of cID#, increment it by 1, and add it to the new subject. For example if your subject is: H&H 2013 allocation.
-It checks if the subject contains the cID# part.✓
-It can't find it, so it checks the folders, and sub-folders for the highest cID#; increment it by 1. ✗
Getting the ID of a single mail as integer is done, because it is just the Val(Right(subjectstring.4)) (It will always be on the right, which is easier for me, because I couldn't find other methods, but they are more than welcome) From these values, it is easy to build the 4 length long string, and insert it to the subject.
My question is, how to get the highest valued cID#-s.
Following Max's advice, my code is based on this, if anyone else has the same problem.
I use the szamid's to set the numbers.
Sub readtextfile()
Dim oFSO As New FileSystemObject
Dim oFS As TextStream
Dim oFSBU As TextStream
Dim filePath As String
Dim filePathBU As String
Dim szamid As Integer
Dim My_filenumber As Integer
filePath = "C:\Casenumber.txt"
filePathBU = "C:\CasenumberBU.txt"
If Not fileExist(filePath) Then GoTo FileDoesntExist
On Error GoTo Err
Set oFS = oFSO.OpenTextFile(filePath, ForReading)
szamid = oFS.Read(7)
szamid = szamid + 1
szamid = CStr(szamid)
oFS.Close
Set oFS = oFSO.OpenTextFile(filePath, ForWriting)
oFS.WriteLine (szamid)
oFS.Close
Set oFSBU = oFSO.OpenTextFile(filePathBU, ForWriting)
oFSBU.WriteLine (szamid)
oFSBU.Close
MsgBox szamid
Exit Sub
FileDoesntExist:
Set oFSBU = oFSO.OpenTextFile(filePathBU, ForReading)
szamid = oFSBU.Read(7)
szamid = szamid + 1
szamid = CStr(szamid)
oFSBU.Close
Const FILENAME = "C:\Casenumber.txt"
My_filenumber = FreeFile
Open FILENAME For Output As #My_filenumber
Close #My_filenumber
Set oFS = oFSO.OpenTextFile(filePath, ForWriting)
oFS.WriteLine (szamid)
oFS.Close
Set oFSBU = oFSO.OpenTextFile(filePathBU, ForWriting)
oFSBU.WriteLine (szamid)
oFSBU.Close
MsgBox szamid
Exit Sub
Err:
MsgBox "Error while reading the file.", vbCritical, vbNullString
oFS.Close
Exit Sub
End Sub
reading all existing e-mails will use some time and resources.
I would keep a text file on the hard-disk, in which you only store the highest value; when reading it and adding +1 for the next mail, also put the new number into your text file.
How-to: see my answer here: read value from text file, Forward email
Max
I need to read all the item titles for all the documents in a SharePoint document library directly into an Array using Excel VBA. I can't seem to successfully use FileSystemObject and I do not want to map the document library to a drive letter as the macro will be distributed and widely used.
The SharePoint site has an https address
I have looked at this thread about referencing scrrun.dll but it does not work because I cannot change the trust settings on my local domain
This thread looked promising, but again it seems to use FileSystemObject which might be my hang up.
This thread on the SharePoint stackexchange site works well for reading in a list of files as a worksheet object, but I don't know how it could be adapted to be pushed directly into an array.
I tend to receive Error 76 "Bad Path", but I am easily able to execute on local (C:) files.
I have tried using a WebDAV address - like the answer I gave to this thread - but it too encounters a "Bad Path" error.
There must be a way to read in the contents of a SharePoint document library directly into an array that does not violate my local security policies and doesn't depend upon an excel worksheet.
Ok I am going to self answer. I'm not 100% thrilled with my solution, but it does suffice within my constraints. Here are the high level points:
Use VBA to create BAT files that have the "Net Use" command within them.
Reference the WebDAV address of the document library and find an available drive letter
I doubt that any of my users already have 26 mapped drives...).
Once the document library is mapped it can be iterated through using FileSystemObject commands and the item titles can be loaded into a two dimensional array.
The code will have to be modified to allow for 3 the listing of subfolders
The location of the file count in the ListMyFiles sub would have to be changed or another dimension would have to be added to the array.
Here is the code - I will try to credit all Stack solutions that were integrated into this answer:
Private Sub List_Files()
Const MY_FILENAME = "C:\BAT.BAT"
Const MY_FILENAME2 = "C:\DELETE.BAT"
Dim i As Integer
Dim FileNumber As Integer
Dim FileNumber2 As Integer
Dim retVal As Variant
Dim DriveLetter As String
Dim TitleArray()
FileNumber = FreeFile
'create batch file
For i = Asc("Z") To Asc("A") Step -1
DriveLetter = Chr(i)
If Not oFSO.DriveExists(DriveLetter) Then
Open MY_FILENAME For Output As #FileNumber
'Use CHR(34) to add escape quotes to the command prompt line
Print #FileNumber, "net use " & DriveLetter & ": " & Chr(34) & "\\sharepoint.site.com#SSL\DavWWWRoot\cybertron\HR\test\the_lab\Shared Documents" & Chr(34) & " > H:\Log.txt"
Close #FileNumber
Exit For
End If
Next i
'run batch file
retVal = Shell(MY_FILENAME, vbNormalFocus)
' NOTE THE BATCH FILE WILL RUN, BUT THE CODE WILL CONTINUE TO RUN.
'This area can be used to evaluate return values from the bat file
If retVal = 0 Then
MsgBox "An Error Occured"
Close #FileNumber
End
End If
'This calls a function that will return the array of item titles and other metadata
ListMyFiles DriveLetter & ":\", False, TitleArray()
'Create code here to work with the data contained in TitleArray()
'Now remove the network drive and delete the bat files
FileNumber2 = FreeFile
Open MY_FILENAME2 For Output As #FileNumber2
Print #FileNumber2, "net use " & DriveLetter & ": /delete > H:\Log2.txt"
Close #FileNumber2
retVal = Shell(MY_FILENAME2, vbNormalFocus)
'Delete batch file
Kill MY_FILENAME
Kill MY_FILENAME2
End Sub
Here is the function that will read through the directory and return the array of file information:
Sub ListMyFiles(mySourcePath As String, IncludeSubFolders As Boolean, TitleArray())
Dim MyObject As Object
Dim mySource As Object
Dim myFile As File
Dim mySubFolder As folder
Dim FileCount As Integer
Dim CurrentFile As Integer
'Dim TitleArray()
Dim PropertyCount As Integer
CurrentFile = 0
Set MyObject = New Scripting.FileSystemObject
Set mySource = MyObject.GetFolder(mySourcePath)
FileCount = mySource.Files.Count
ReDim TitleArray(0 To FileCount - 1, 4)
'On Error Resume Next
For Each myFile In mySource.Files
PropertyCount = 1
TitleArray(CurrentFile, PropertyCount) = myFile.Path
PropertyCount = PropertyCount + 1
TitleArray(CurrentFile, PropertyCount) = myFile.Name
PropertyCount = PropertyCount + 1
TitleArray(CurrentFile, PropertyCount) = myFile.Size
PropertyCount = PropertyCount + 1
TitleArray(CurrentFile, PropertyCount) = myFile.DateLastModified
CurrentFile = CurrentFile + 1
Next
'The current status of this code does not support subfolders.
'An additional dimension or a different counting method would have to be used
If IncludeSubFolders = True Then
For Each mySubFolder In mySource.SubFolders
Call ListMyFiles(mySubFolder.Path, True, TitleArray())
Next
End If
End Sub
Thank you to Chris Hayes for his answer to find empty network drives; thank you to Kenneth Hobson on ozgrid for his expanded answer on listing files in a directory. The rest of the code is ancient and I dredged it out of a folder I last touched in 2010.
Trying to use Excel VBA to capture all the file attributes from files on disk, including extended attributes. Was able to get it to loop through the files and capture the basic attributes (that come from the file system):
File Path
File Name
File Size
Date Created
Date Last Accessed
Date Last Modified
File Type
Would also like to capture the extended properties that come from the file itself:
Author
Keywords
Comments
Last Author
Category
Subject
And other properties which are visible when right clicking on the file.
The goal is to create a detailed list of all the files on a file server.
You say loop .. so if you want to do this for a dir instead of the current document;
Dim sFile As Variant
Dim oShell: Set oShell = CreateObject("Shell.Application")
Dim oDir: Set oDir = oShell.Namespace("c:\foo")
For Each sFile In oDir.Items
Debug.Print oDir.GetDetailsOf(sFile, XXX)
Next
Where XXX is an attribute column index, 9 for Author for example.
To list available indexes for your reference you can replace the for loop with;
for i = 0 To 40
debug.? i, oDir.GetDetailsOf(oDir.Items, i)
Next
Quickly for a single file/attribute:
Const PROP_COMPUTER As Long = 56
With CreateObject("Shell.Application").Namespace("C:\HOSTDIRECTORY")
MsgBox .GetDetailsOf(.Items.Item("FILE.NAME"), PROP_COMPUTER)
End With
You can get this with .BuiltInDocmementProperties.
For example:
Public Sub PrintDocumentProperties()
Dim oApp As New Excel.Application
Dim oWB As Workbook
Set oWB = ActiveWorkbook
Dim title As String
title = oWB.BuiltinDocumentProperties("Title")
Dim lastauthor As String
lastauthor = oWB.BuiltinDocumentProperties("Last Author")
Debug.Print title
Debug.Print lastauthor
End Sub
See this page for all the fields you can access with this: http://msdn.microsoft.com/en-us/library/bb220896.aspx
If you're trying to do this outside of the client (i.e. with Excel closed and running code from, say, a .NET program), you need to use DSOFile.dll.
'vb.net
'Extended file stributes
'visual basic .net sample
Dim sFile As Object
Dim oShell = CreateObject("Shell.Application")
Dim oDir = oShell.Namespace("c:\temp")
For i = 0 To 34
TextBox1.Text = TextBox1.Text & oDir.GetDetailsOf(oDir, i) & vbCrLf
For Each sFile In oDir.Items
TextBox1.Text = TextBox1.Text & oDir.GetDetailsOf(sFile, i) & vbCrLf
Next
TextBox1.Text = TextBox1.Text & vbCrLf
Next
I was finally able to get this to work for my needs.
The old voted up code does not run on windows 10 system (at least not mine). The referenced MS library link below provides current examples on how to make this work. My example uses them with late bindings.
https://learn.microsoft.com/en-us/windows/win32/shell/folder-getdetailsof.
The attribute codes were different on my computer and like someone mentioned above most return blank values even if they are not. I used a for loop to cycle through all of them and found out that Title and Subject can still be accessed which is more then enough for my purposes.
Private Sub MySubNamek()
Dim objShell As Object 'Shell
Dim objFolder As Object 'Folder
Set objShell = CreateObject("Shell.Application")
Set objFolder = objShell.NameSpace("E:\MyFolder")
If (Not objFolder Is Nothing) Then
Dim objFolderItem As Object 'FolderItem
Set objFolderItem = objFolder.ParseName("Myfilename.txt")
For i = 0 To 288
szItem = objFolder.GetDetailsOf(objFolderItem, i)
Debug.Print i & " - " & szItem
Next
Set objFolderItem = Nothing
End If
Set objFolder = Nothing
Set objShell = Nothing
End Sub
Lucky discovery
if objFolderItem is Nothing when you call
objFolder.GetDetailsOf(objFolderItem, i)
the string returned is the name of the property, rather than its (undefined) value
e.g. when i=3 it returns "Date modified"
Doing it for all 288 values of I makes it clear why most cause it to return blank for most filetypes
e.g i=175 is "Horizontal resolution"