Der Neustart der PowerShell-Console brachte dann den Erfolg. Es kann manchmal so einfach sein.
Beiträge von _mk_
-
-
@All
Sehr gerne möchte ich das AutoItX Modul für PowerShell nutzen. Auf meinem Arbeitsplatz, auf dem ich AutoIt installiert ist, funktioniert es einwandfrei. Jetzt möchte ich diese Cmdlets auf Rechner nutzen, auf denen kein AutoIt installiert ist. Die benötigen Dateien habe ich, wie in der Hilfe beschrieben ist, auf die Rechner kopiert und die Sicherheitsblockade der Dateien aufgehoben. Leider schlägt der Versuch, das Modul zu importieren, mit dieser Fehlermeldung fehl:
Die Datei AutoItX.dll habe ich zusätzlich auf einem Testzielsystem registriert. Aber das blieb auch ohne Erfolg.
Hat jemand eine Idee? Im Netz habe ich dazu nicht gefunden. Auf den Zielsystemen möchte ich AutoIt nicht installieren.
Danke im Voraus.
-
Ich muss auf 300 Rechnern ein MSI installen und brauch eine Möglichkeit einen RunAsWait auf den Rechnern in der AD auszuführen.
MSI-Pakete lassen sich per Gruppenrichtlinien verteilen.
-
_mk_ (nur so am Rande) :
Variablendeklarationen mit Dim werden i.a. nicht (mehr) empfohlen.
Man verwendet i.d.R. Global oder Local , je nach Scope.
Danke für den Hinweis. In komplexeren Skripte bzw. Skripte, die produktiv im Einsatz sind, verwende ich für die Variablendeklaration die Schlüsselwörter Global und Local. Künftig werde ich Dim vermeiden.
-
Warum hier noch mal -1?
Arrays in AutoIt und in den meisten Programmiersprachen sind nullbasiert.
AutoIt
Alles anzeigen; Erzwingt Variablendeklaration AutoItSetOption("MustDeclareVars", 1) Dim Const $SKIP_FIRST_LINES = 8 Dim Const $SKIP_LAST_LINES = 15 ; File_Constants Dim Const $FC_OVERWRITE = 1 Dim Const $FO_OVERWRITE = 2 ; --- ; Nach Text-Dateien im aktuellen Verzeichnis suchen Dim $search = FileFindFirstFile("*.txt") ; War die Suche erfolgreich? If($search = -1) Then ConsoleWrite("- Es wurden keine Text-Dateien gefunden!") While 1 ; Naechste Dateinamen zurueckgeben Dim $fileName = FileFindNextFile($search) ; Sind weitere passende Dateien vorhanden? If @error Then ExitLoop ; Gesamten Dateiinhalt in ein Array einlesen Dim $array = FileReadToArray($fileName) If(@error = 0) Then ; Sicherungskopie anlegen FileCopy($fileName, $fileName & ".bak", $FC_OVERWRITE) ; Array zeilenweise in Datei schreiben Dim $fileOpen = FileOpen($fileName, $FO_OVERWRITE) For $i = $SKIP_FIRST_LINES To UBound($array) - $SKIP_LAST_LINES - 1 FileWriteLine($fileOpen, $array[$i]) Next FileClose($fileOpen) Else ; @error : 1 = Fehler beim Oeffenen, 2 = leere Datei ConsoleWrite(StringFormat("! Beim Einlesen der Datei %s ist der Fehler %s aufgetreten. %s", $fileName, @error, @CRLF)) EndIf WEnd FileClose($search)
-
Das Entfernen aus dem Schnellzugriff funktioniert leider nicht. Meine Internetrecherche bliebt bisher erfolglos, warum das Verb "unpinfromhome" nicht ausgeführt wird.
Code
Alles anzeigenFunc QuickAccess($Path, $Action) Enum $ERROR_SUCCESS = 0, _ $ERROR_OCCURRED, _ $ERROR_PATH_NOT_EXIST, _ $ERROR_PATH_NOT_FOLDER, _ $ERROR_NOT_VALID_PARAMETER, _ $ERROR_PATH_IS_PINNED, _ $ERROR_PATH_NOT_PINNED If Not FileExists($Path) Then Return SetError($ERROR_OCCURRED, $ERROR_PATH_NOT_EXIST) If(StringInStr(FileGetAttrib($Path), "D") = 0) Then Return SetError($ERROR_OCCURRED, $ERROR_PATH_NOT_FOLDER) Dim $Shell = ObjCreate("Shell.Application") Dim $Exists = False Dim $QuickAccess = $Shell.Namespace("shell:::{679f85cb-0220-4080-b29b-5540cc05aab6}") For $Item In $QuickAccess.Items() If(StringCompare($Item.Path, $Path) = 0) then $Exists = True ExitLoop EndIf Next Dim $FolderItem = $Shell.Namespace($Path).Self Switch $Action Case "Pin" If($Exists) then ;ConsoleWrite(StringFormat("-> WARNING: '%s' ist bereits angeheftet.%s", $FolderItem.Path, @CRLF)) Return SetError($ERROR_OCCURRED, $ERROR_PATH_IS_PINNED) Else $FolderItem.InvokeVerb("pintohome") EndIf Case "Unpin" If Not($Exists) Then ;ConsoleWrite(StringFormat("-> WARNING: '%s' ist nicht angeheftet.%s", $FolderItem.Path, @CRLF)) Return SetError($ERROR_OCCURRED, $ERROR_PATH_NOT_PINNED) Else ;For $Verb In $FolderItem.Verbs() ; ConsoleWrite($Verb.Name & @crlf) ;Next $FolderItem.InvokeVerb("unpinfromhome") EndIf Case Else Return SetError($ERROR_OCCURRED, $ERROR_NOT_VALID_PARAMETER) EndSwitch EndFunc ;==>QuickAccess
-
Damit Du Dir die Zeichenkettenoperationen ersparst, würde ich direkt auf die Eigenschaft Status zugreifen.
-
So fragst Du den Dienststatus mit Hilfe der PowerShell ab. Alternative zum Get-Service CmdLet ist das Konsolenprogramm sc.exe.
-
Interessant ist natürlich die Logik, dass asynchrone Uhrzeit als falscher Benutzer oder Passwort interpretiert wird - that's M$.
Nicht Microsoft. Kerberos ist im RFC 4120 - The Kerberos Network Authentication Service definiert. Lt. RFC 4430 - Kerberized Internet Negotiation of Keys darf der Zeitunterschied nicht länger als fünf Minuten betragen.
-
Entweder Du rufst ein PowerShell-Skript aus Deiner AutoIt-Oberfläche auf und übergibst die benötigen Parameter an das PowerShell-Skript ...
Spoiler anzeigen
AutoIt
Alles anzeigen#include <ButtonConstants.au3> #include <EditConstants.au3> #include <GUIConstantsEx.au3> #include <StaticConstants.au3> #include <WindowsConstants.au3> #Region ### START Koda GUI section ### Form= $Form1 = GUICreate("Form1", 434, 209, 197, 178) $Input1 = GUICtrlCreateInput("Input1", 168, 40, 185, 21) $Radiobutton1 = GUICtrlCreateRadio("lesen", 168, 80, 65, 17) $Button1 = GUICtrlCreateButton("Erstellen", 168, 176, 75, 25) $Radiobutton2 = GUICtrlCreateRadio("lesen und schreiben", 168, 96, 129, 17) $Label1 = GUICtrlCreateLabel("Rechte", 24, 80, 62, 24) GUICtrlSetFont(-1, 12, 800, 0, "MS Sans Serif") $Label2 = GUICtrlCreateLabel("Zugriff für", 21, 127, 84, 24) GUICtrlSetFont(-1, 12, 800, 0, "MS Sans Serif") $Label3 = GUICtrlCreateLabel("Ordnernamen", 24, 44, 113, 24) GUICtrlSetFont(-1, 12, 800, 0, "MS Sans Serif") $Input2 = GUICtrlCreateInput("Input2", 168, 128, 185, 21) $Button2 = GUICtrlCreateButton("Abbrechen", 280, 176, 75, 25) GUISetState(@SW_SHOW) #EndRegion ### END Koda GUI section ### While 1 $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE Exit Case $Button1 $Path = StringFormat("H:\Share_Test\%s", GUICtrlRead($Input1)) DirCreate($path) $Principal = StringFormat("DOMAIN\%s", GUICtrlRead($Input2)) Select Case BitAND(GUICtrlRead($Radiobutton1), $GUI_CHECKED) $Rights = "ReadAndExecute" Case BitAND(GUICtrlRead($Radiobutton2), $GUI_CHECKED) $Rights = "ReadAndExecute, Write" EndSelect Run(StringFormat('PowerShell.exe -noprofile -executionpolicy Bypass -file "c:\set-permission.ps1" -Path %s -Principal %s -Rights %s', _ $Path, $Principal, $Rights)) EndSwitch WEnd
Set-Permission.ps1
Code
Alles anzeigenParam( [string] $Path, [string] $Principal, [String] $Rights ) $acl = Get-Acl -Path $Path # ACL vorher: # $acl | Format-List $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule( $Principal, # identity [System.Security.AccessControl.FileSystemRights]$Rights, # fileSystemRights ([System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [System.Security.AccessControl.InheritanceFlags]::ObjectInherit), # inheritanceFlags [System.Security.AccessControl.PropagationFlags]::InheritOnly, # propagationFlags [System.Security.AccessControl.AccessControlType]::Allow) # type $acl.AddAccessRule($accessRule) Set-Acl -Path $Path -AclObject $acl # ACL nachher: # $acl | Format-List # Write-Host "Press any key to continue ..." # $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
... oder Du lässt PowerShell die gesamte Arbeit machen.
Spoiler anzeigen
Code
Alles anzeigen$xaml = [xml]@" <?xml version="1.0" encoding="utf-8"?> <Window x:Class="test.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="test" SizeToContent="WidthAndHeight" WindowStyle="ToolWindow" ResizeMode="NoResize"> <StackPanel Orientation="Vertical" Margin="10"> <StackPanel Orientation="Horizontal" Margin="5"> <Label Width="100">Ordnername</Label> <TextBox Name="txtFolder" Width="300"></TextBox> </StackPanel> <StackPanel Orientation="Horizontal" Margin="5"> <Label Width="100">Rechte</Label> <RadioButton Name="optRead" Margin="5">Lesen</RadioButton> <RadioButton Name="optReadWrite" Margin="5">Lesen und Schreiben</RadioButton> </StackPanel> <StackPanel Orientation="Horizontal" Margin="5"> <Label Width="100">Zugriff für ...</Label> <TextBox Name="txtPrincipal" Width="300"></TextBox> </StackPanel> <StackPanel Orientation="Horizontal" HorizontalAlignment="Right"> <Button Name="butCreate" Width="80" Margin="5">Erstellen</Button> <Button Name="butCancel" Width="80" Margin="5">Abbrechen</Button> </StackPanel> </StackPanel> </Window> "@ $xaml.Window.RemoveAttribute("x:Class") Add-Type -AssemblyName PresentationFramework $xmlReader = New-Object System.Xml.XmlNodeReader -ArgumentList $xaml $window = [System.Windows.Markup.XamlReader]::Load($xmlReader) # Steuerelemente ansprechen, mit denen später etwas passieren soll: $textboxFolder = $window.FindName("txtFolder") $textboxPrincipal = $window.FindName("txtPrincipal") $radiobuttonRead = $window.FindName("optRead") $radiobuttonReadWrite = $window.FindName("optReadWrite") $buttonCreate = $window.FindName("butCreate") $buttonCancel = $window.FindName("butCancel") # Ereignisse der Steuerelemente mit Aktion versehen: $buttonCreate.Add_Click( { $window.DialogResult = $true} ) $buttonCancel.Add_Click( { $window.DialogResult = $false} ) $dialogResult = $window.ShowDialog() if ($dialogResult -eq $true) { $directory = New-Item -Path $textboxFolder.Text -ItemType Directory $acl = Get-Acl -Path $directory # ACL vorher: # $acl | Format-List If ($checkboxRead.IsChecked) { $Right = [System.Security.AccessControl.FileSystemRights]::ReadAndExecute } If ($radiobuttonReadWrite.IsChecked) { $Right = ([System.Security.AccessControl.FileSystemRights]::ReadAndExecute -bor [System.Security.AccessControl.FileSystemRights]::Write) } # https://msdn.microsoft.com/de-de/library/sfe70whw(v=vs.110).aspx $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule( $textboxPrincipal.Text, # identity $Right, # fileSystemRights ([System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [System.Security.AccessControl.InheritanceFlags]::ObjectInherit), # inheritanceFlags [System.Security.AccessControl.PropagationFlags]::InheritOnly, # propagationFlags [System.Security.AccessControl.AccessControlType]::Allow) # type $acl.AddAccessRule($accessRule) Set-Acl -Path $directory -AclObject $acl # ACL nachher: # $acl | Format-List } else { Write-Warning "Abbruch durch den Benutzer." }
-
-
Falls Du nicht auf das Durchsuchen der Registry festgelegt bist, könntest Du das Programm per WMI deinstallieren.
AutoIt; https://msdn.microsoft.com/en-us/library/aa394378(v=vs.85).aspx Dim $WQL = 'SELECT * FROM Win32_Product WHERE Name LIKE "%Workplace Protect%"' ; Bitte anpassen!!! Dim $Softwares = ObjGet('winmgmts:\root\cimv2').ExecQuery($WQL) ; As SWbemObjectSet For $Software In $Softwares ConsoleWrite($Software.Name & @CRLF) ; Software.Uninstall() Next
-
Das Skript als Kommandozeilenprogramm kompilieren. Das Skript folgendermaßen in der Eingabeaufforderung ausführen: <scriptname>.exe /name alg > <txtdatei>.txt. In der Textdatei findest Du die Skriptausgabe.
AutoIt
Alles anzeigen#Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Change2CUI=y ; <-- Skript als Kommandozeilenprogramm kompilieren #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** ; Das kompilierte Skript mit den Kommandozeilenparamter /name oder -name ausführen. ; Beispiel: <scriptname>.exe /name alg ; WICHTIG: Keine Fehlerbehandlung!!! If (StringLower($CmdLine[1]) = '/name') Or (StringLower($CmdLine[1]) = '-name') Then _GetService($CmdLine[2]) ; Link: https://msdn.microsoft.com/en-us/library/aa394418(v=vs.85).aspx Func _GetService($ServiceName) Local $Services = ObjGet('winmgmts:\root\cimv2').ExecQuery('SELECT * FROM Win32_Service WHERE Name="' & $ServiceName & '"') ; As SWbemObjectSet For $Service In $Services ConsoleWrite('Name ........: ' & $Service.Name & @CRLF) ConsoleWrite('Displayname .: ' & $Service.DisplayName & @CRLF) ConsoleWrite('Pathname ....: ' & $Service.PathName & @CRLF) Next ; $Service EndFunc ;==>_GetService
-
AutoIt
Alles anzeigen; Beispiele _GetService('alg') _GetService('eventlog') ; Link: https://msdn.microsoft.com/en-us/library/aa394418(v=vs.85).aspx Func _GetService($ServiceName) Local $Services = ObjGet('winmgmts:\root\cimv2').ExecQuery('SELECT * FROM Win32_Service WHERE Name="' & $ServiceName & '"') ; As SWbemObjectSet For $Service In $Services ConsoleWrite($Service.Name & @CRLF) ConsoleWrite($Service.DisplayName & @CRLF) ConsoleWrite($Service.PathName & @CRLF) Next ; $Service EndFunc ;==>_GetService
-
Grundsätzlich kannst Du davon ausgehen, dass die statischen Methoden von COM nicht unterstützt werden. (In der MSDN werden diese Methoden mit einem gelben S markiert)
Gerne bemühe ich kurz die PowerShell, um schnell zu schauen, was mit dem COM-Objekt möglich ist.
Hier siehst Du, was der Aufruf ausgibt.
Spoiler anzeigen
-
Sry, hätte mir auffallen müssen, dass die Funktion Sekunden zurückgibt und ich dann den Rückgabewert umrechne. Da hatte ich den Wald vor lauter Bäume nicht mehr gesehen.
-
Heute habe ich die aktuelle Version Deiner AD-UDF herunterladen und ich wollte daraus die Funktion __AD_Int8ToSec verwenden. Dabei ist mir aufgefallen, dass sich dort ein Fehler eingeschlichen hat. Die Zeile Return -($lngHigh * (2 ^ 32) + $lngLow) / (10000000) muss Return -($lngHigh * (2 ^ 32) + $lngLow) / (60 * 10000000) lauten. Ebenfalls solltest Du den documentation header der Funktion überarbeiten. Laut Dokumentation erwartet die Funktion die Parameter $iLow und $iHigh. Im Funktionskopf hast Du aber nur den Parameter $oInt8 definiert.
-
Da Du nicht auf eine Sprache festgelegt bist, habe ich Dir ein Powershell-Skript erstellt. Du kannst das Powershell-Skript mit Deinem AutoIt-Skript ausführen und die Ausgabe weiterverarbeiten.
Code
Alles anzeigen# Pfade an die Umgebung anpassen !!! $OutFile = "C:\dumps\permission.csv" $Path = "\\<Computer>\<Share>\" Remove-Item -Path $OutFile -Force -ErrorAction SilentlyContinue $Header = "Verzeichnis;Besitzer;Benutzer/Gruppe;Recht;Zugriff;Geerbt;Vererbungsflag" Add-Content -Value $Header -Path $OutFile $AccessRules = Get-ChildItem -Path $Path -Recurse -Directory -PipelineVariable Dir -ErrorAction SilentlyContinue | ForEach-Object { Get-Acl -Path $PSItem.FullName -PipelineVariable ACL | Select-Object -ExpandProperty Access | Select-Object @{Name="Directory"; Expression={$Dir.Fullname}}, @{Name="Owner"; Expression={$ACL.Owner}}, IdentityReference, FileSystemRights, AccessControlType, IsInherited, InheritanceFlags } Foreach($Rule In $AccessRules) { $Content = $Rule.Directory + ";" + $Rule.Owner + ";" + $Rule.IdentityReference + ";" + $Rule.FileSystemRights + ";" + $Rule.AccessControlType + ";" + $Rule.IsInherited + ";" + $RUle.InheritanceFlags Add-Content -Value $Content -Path $OutFile }
-
Nur der Vollständigkeit halber die Portierung von Diskpart nach PowerShell:
CodeGet-Disk | Where-Object -FilterScript {$PSItem.Bustype -eq 'USB'} | Clear-Disk -RemoveData -Confirm:$false -PassThru | New-Partition -UseMaximumSize -IsActive -AssignDriveLetter | Format-Volume -FileSystem NTFS
Hier findest Du eine Auflistung aller CmdLets aus dem Modul Windows Storage Management.
-
Da hast Du recht. Ein Skript ist sehr statisch. Über das Auslesen mit Hilfe von list disk kann ich mir auch nicht sicher sein, dass ich genau das richtige Laufwerk erwische. Die Ausgabe von list disk liefert nicht genügend Informationen. Auf Grund der Größe kann ich nicht auf den richtigen Wechseldatenträger schließen. Da musste ich schon jeden Datenträger auswählen und mir die Details anschauen. Oder ich erstelle mir dynamisch mein Datenträgerpartitionierungsskript, indem ich vorher in der PowerShell mir die USB-Sticks auswerten lasse: Get-Disk | Where-Objekt -FilterScript {$PSItem.Bustype -eq 'USB'}. Die PowerShell kann ich auch aus dem AutoIT-Skript ausführen.