Главная

Wednesday, 8 November 2017

Совместимость между VBA, VBScript и Powershell.

Всем привет.

Как оказалось наш Excel это мега-инструмент для администратора!

В код VBA в Excel можно легко вставлять блоки VBS кода и все будет успешно работать.

Вот вам пример простенькой смеси из VBА и VBS кода, MyVBScript() определяеят версию ОС, 7ка или нет, и пишет результат в активную ячейку.
Sub MyVBScript()
On Error Resume Next
Set objCollection = GetObject("winmgmts:\\.\root\cimv2").ExecQuery("SELECT Name FROM Win32_OperatingSystem")
For Each objItem In objCollection
    strOS = objItem.Name
Next
'MsgBox strOS
ActiveCell.Select
If InStr(1, strOS, " Vista ", vbTextCompare) > 0 Or InStr(strOS, " 7 ") > 0 Then
    ActiveCell.FormulaR1C1 = "Windows 7"
Else
    ActiveCell.FormulaR1C1 = "It isn't Win7"
End If

End Sub


Здорово, не правда ли?
Но возьмем пример попрактичнее. Администратору надо было вручную поменять пароль главного админа на всех хостах в локальной сети. Но администратор был в меру ленив и решил использовать любимый Excel!

Он открыл Excel и поступил так:
- заполнил список хостов в 1-ю колонку начиная с 2-го ряда "R2С1"
- заполнил 2-ю колонку паролями
- в 3-й колонке будет результат операции "Yes/No"
- в 4-й описание ошибки
Далее написал вот такой VBA+VBS код:


Private Sub CommandButton1_Click()
 intRow = 2
Do
 If Cells(intRow, 1).Value = "" Then
 Exit Do
 End If
strComputer = Cells(intRow, 1).Value
On Error Resume Next
'соединяемся с хостом strComputer
Set objUser = GetObject("WinNT://" & strComputer & "/Administrator, User")
'хост strComputer оказался недоступен
If Err.Number 0 Then
 Cells(intRow, 3).Value = "No"
 Cells(intRow, 4).Value = Err.Description
 Else
  'меняем пароль на новый strNewPassword
  strNewPassword = Cells(intRow, 2).Value
  objUser.SetPassword strNewPassword
  objUser.SetInfo
  If Err.Number 0 Then
  Cells(intRow, 3).Value = "No"
  Cells(intRow, 4).Value = Err.Description
  Err.Clear
  Else
  Cells(intRow, 3).Value = "Yes"
  Cells(intRow, 4).Value = ""
  End If
End If
 intRow = intRow + 1
 Loop
End Sub


Запустил его на выполнение, и через пару минут получил готовый Sheet со статусами хостов где поменялся пароль или нет.


Раз есть такая совместимость между VBА и VBS, то как же дела с PowerShell?


Из VBA-скрипта можно вызвать внешний скрипт PowerShell:
Dim retval As Variant
retval = Shell("PowerShell ""D:\MyScript.ps1""", vbNormalFocus)


Ничего удивительного, ведь так можно вызвать любую программу из VBA.
Можно рискнуть и прописать весь вызов PowerShell внутри VBA чтобы обойтись без внешнего файла:

Dim retval As Variant
Dim pscmd As String
pscmd = "PowerShell -Command ""{Get-ScheduledTask -TaskName 'My Task' -CimSession MYLAPTOP}"""
retval = Shell(pscmd, vbNormalFocus)


Но опять же это получается внешний вызов через Shell-функцию.


А вот такого же легкого внедрения кода PowerShell в VBA как можно делать с VBScript я не нашел.


Обратные вызовы из Powershell или VBScript к Excel работают, как и раньше, через СОМ-обьекты.

Из VBScript (Gerry Hickman):
var objXL;
var objSheet;
Set objXL = CreateObject("Excel.Application")
objXL = GetObject("c:\\Scripts\\quotas.xls");
objXL.Application.Visible = true;
objXL.Parent.Visible = true;
objXL.Parent.Windows(1).Visible = true;
objXL.Worksheets.Add();
objSheet = objXL.Worksheets(1);
objSheet.Name = getDateTime();
objSheet.Visible = true;
objSheet.Activate();
objSheet.Cells(r,1).Value = "Folder";
objSheet.Cells(r,2).Value = "Size";
objXL.Parent.Windows(1).Visible = true;
objXL.Parent.Visible = true;
objXL.Save();
objXL.Parent.UserControl = true;
objXL.Application.Quit();
objXL = null;


Из Powershell:
$b = New-object -ComObject Excel.Application
$b.Visible= $true
$c = $b.WorkBooks.Add()
$d = $c.Sheets.Add()
$d.Cells.Item(1,1) ="Process Name"
$d.Cells.Item(2,1) =$a.Name
$d.Cells.Item(1,2) ="ID"
$d.Cells.Item(2,2) =$a.ID


Успехов.

1 comment:

  1. ' Процедура конвертирования экспортированных файлов с данными
    Private Sub Coding_File_Data()
    Const PSS_File As String = "CSV-convert.ps1" 'Наименование скрипта конвертера
    Const CSVDiv As String = """;""" ' Символ разделитель полей в экспортиров. файлах
    Const TxtDiv As String = """`t""" ' Символ разделитель полей в импортируем. файлах
    Dim FSOObj As Object ' Объект файловой системы
    Dim TSOObj As Object ' Объект текстового файла
    Dim PSSS2F As String ' Строка текста передаваемая в скрипт Powershell
    Dim PSSS2I As String ' Строка инициализации для интерпретатора команд
    ' Собираем собственно сам скрипт для запуска Powershell
    PSSS2F = _
    "Get-ChildItem -Path $PSScriptRoot -Filter *" & Out_FileExts & " | " & _
    "ForEach-Object { " & Chr(13) & "$Text = Import-CSV -Path $_.FullName" & _
    " -Encoding Default -Delimiter " & TxtDiv & Chr(13) & "$Text | Export-Csv" & _
    " -Path $_.FullName" & " -Encoding UTF8 -Delimiter " & CSVDiv & " -NoTypeInformation}" & _
    Chr(13) & "New-Item -Path $PSScriptRoot -Name " & Out_FileExts & " -ItemType Directory | " & _
    "Out-Null" & Chr(13) & "Move-Item -Path $PSScriptRoot\*" & Out_FileExts & _
    " -Destination $PSScriptRoot\" & Out_FileExts & "\ -Force | Out-Null" & _
    Chr(13) & "If ((Get-Variable Text | Out-Null) -ne $Null) {Remove-Variable -Name Text}"
    'Инициализируем объект файловой системы
    Set FSOObj = CreateObject("Scripting.FileSystemObject")
    'Объявляем объект для записи всех данных из единой строки в файл
    Set TSOObj = FSOObj.CreateTextFile(ThisWorkbook.Path & "\" & PSS_File, 8, False)
    'Построчно записываем данные в текстовый файл
    With TSOObj
    .WriteLine PSSS2F
    .Close
    End With
    'Уничтожаем неиспользуемые объекты высвобождая память
    Set TSOObj = Nothing
    Set FSOObj = Nothing
    ' Собираем строку запуска для командного интерпретатора
    PSSS2I = "Powershell.exe -WindowStyle Hidden -File """ & _
    ThisWorkbook.Path & "\" & PSS_File & """"
    ' Получаем результат запуска нашего скрипта
    Call WaitForProcessToEnd(PSSS2I, vbHide)
    'Удаляем созданный файл со скриптом с диска
    Kill ThisWorkbook.Path & "\" & PSS_File
    End Sub

    ReplyDelete

А что вы думаете по этому поводу?