spsman
Goto Top

Powershell: Aufgabe im Hintergrund MsgBox in Vordergrund

Hallo,

Lösung Siehe : Aufgabenplanung: Powershell Script im Hintergrund mit Userbenachrichtigung im Vordergrund

ich habe ein Script in dem ich Dateien mit Aufgabenplaner von A nach B Kopiere. Die Pfade stehen in einer CSV.
Das Script lasse ich im Hintergrund laufen, jedoch möchte ich wenn ein Pfad nicht Erreichbar ist eine Info ausgeben, was leider noch nicht funktioniert. Habt Ihr eine Idee zur umsetzung?

CSV:
Quelle	Ziel
C:\Temp\source	C:\Temp\dest

Powershell:
#Aktuellen Standardpfad setzen
Set-Location "C:\Temp"  

If (Test-Connection Server01 -Count 1 -quiet)
{
    $csvpath = '.\Sync.CSV'  

    $Aufgaben = Import-Csv $csvpath -Delimiter ([regex]::match((gc $csvpath -Raw),'^("[^"]*"|[^,;]+)\s*([,;])').Groups[2].Value)  
    # Zeile der CSV durchgehen
    Foreach ($Aufgabe in $Aufgaben)
        {
        # gültige Pfad in CSV eingetragen?
        If (!(Test-Path -Path $Aufgabe.Quelle))
            {
                [System.Windows.Forms.MessageBox]::Show("Verzeichnis: "+$Aufgabe.Quelle+" nicht gefunden.")  
            }
        elsif (!(Test-Path -Path $Aufgabe.Ziel))
            {
                [System.Windows.Forms.MessageBox]::Show("Verzeichnis: "+$Aufgabe.Ziel+" nicht gefunden.")  
            }
        else
            {
            Write-Output ("Pfad "+$Aufgabe.Ziel+"  gefunden")  
            $file = (Get-ChildItem $Aufgabe.Quelle -File -Recurse| Where {$_.Name -like "*.zap*"}| sort lastwritetime | select -last 1)  
            $ZielDatei= $Aufgabe.Ziel+"\"+"RW_"+$file.Name  
            #Zieldatei schon vorhanden?
            If (-NOT(Test-Path -Path $ZielDatei -PathType Leaf))
                {
                Write-Output ("Kopiere Datei "+$file.Name+" nach "+$ZielDatei)  
                Copy-Item $file.FullName -Destination $ZielDatei

                }
            }
            
        }
}

Danke.

Content-ID: 4743938752

Url: https://administrator.de/forum/powershell-aufgabe-im-hintergrund-msgbox-in-vordergrund-4743938752.html

Ausgedruckt am: 26.12.2024 um 10:12 Uhr

Crusher79
Crusher79 24.11.2022 um 08:51:08 Uhr
Goto Top
Hallo,

wie lässt du es denn im Hintergrund laufen? Unter welchen User Kontext?

Zum ausblenden des Fensters gibt es ja mehrere Möglichkeiten. VBS Aufruft und das ganze auf hidden setzen oder ähnliches. Wenn es ausgeblendet ist, sollte eig. die GUI funktionieren.

mfg Crusher
4400667902
4400667902 24.11.2022 aktualisiert um 10:47:12 Uhr
Goto Top
Aufgabe im User-Kontext ausführen lassen und im Skript Konsole einfach ausblenden lassen
Add-Type –MemberDefinition '[DllImport("user32.dll")]public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);' -name Window -namespace tools  
[void][Tools.Window]::ShowWindow((Get-Process -id $pid).MainWindowHandle, 0)
Evt, Message-Boxes erscheinen dann trotzdem noch.

Alternativ wenn Aufgabe mit anderem Account ausgeführt wird per msg.exe die Nachricht dem User schicken.

Oder das hier wäre auch noch eine Möglichkeit, gerade noch gefunden:
Popup erzeugen in Windows, dessen Inhalt nicht mitgeloggt wird

Uk.
TK1987
TK1987 24.11.2022 um 11:10:42 Uhr
Goto Top
Moin,

Zitat von @4400667902:
Aufgabe im User-Kontext ausführen lassen und im Skript Konsole einfach ausblenden lassen
Add-Type –MemberDefinition '[DllImport("user32.dll")]public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);' -name Window -namespace tools  
[void][Tools.Window]::ShowWindow((Get-Process -id $pid).MainWindowHandle, 0)
Dafür reicht es auch, Powershell einfach mit dem Argument
-WindowStyle Hidden
zu starten face-wink

In beiden fällen ploppt dann aber natürlich noch kurz das Konsolenfenster auf bis der Code oder das Argument verabeitet wurde. Das wiederum lässt sich nur verhindern, indem man sich eine Binärdatei baut, die den Powershell-Code direkt im Hintergrund ausführt.

Gruß Thomas
4400667902
4400667902 24.11.2022 aktualisiert um 11:18:26 Uhr
Goto Top
Jepp klar war nur eine andere Variante.
Crusher79
Crusher79 24.11.2022 um 11:18:35 Uhr
Goto Top
Zitat von @TK1987:

In beiden fällen ploppt dann aber natürlich noch kurz das Konsolenfenster auf bis der Code oder das Argument verabeitet wurde. Das wiederum lässt sich nur verhindern, indem man sich eine Binärdatei baut, die den Powershell-Code direkt im Hintergrund ausführt.

Oder mit VBS und Hidden. Was besseres gibt es nicht oder? Ich bin immer noch bei VBS hängengebieben....

Ich such mir da auch immer einen Wolf.

Dim objShell,objFSO,objFile

Set objShell=CreateObject("WScript.Shell")  
Set objFSO=CreateObject("Scripting.FileSystemObject")  

'enter the path for your PowerShell Script  
 strPath="c:\ps\archiv_pdf.ps1"  

'verify file exists  
 If objFSO.FileExists(strPath) Then
   'return short path name  
   set objFile=objFSO.GetFile(strPath)
   strCMD="powershell -ExecutionPolicy Bypass -nologo -command " & Chr(34) & "&{" &_  
    objFile.ShortPath & " " & WScript.Arguments(0) &" "& WScript.Arguments(1) &" "& WScript.Arguments(2) & "}" & Chr(34)  
   'Uncomment next line for debugging  
   'WScript.Echo strCMD  

  'use 0 to hide window  
   objShell.Run strCMD,0

Else

  'Display error message  
   WScript.Echo "Failed to find " & strPath  
   WScript.Quit

End If
4400667902
4400667902 24.11.2022 aktualisiert um 11:27:17 Uhr
Goto Top
Wenn du per VBS hidden startest werden aber auch sämtliche evt. Messageboxen mit versteckt weil der ganze Prozess hidden startet und genau das will er ja nicht ...

Man kann sich aber auch in echten Hintergrund-Prozessen das Konsolen-Token krallen und dort Anwendungen im Kontext des sichtbaren Users ausführen lassen, das geht per win32 impersonation wird aber etwas länger.
Oder man nimmt eben einen Scheduled Task und lässt den mit einem Gruppen-Account ausführen das wird dann auch wieder sichtbar für den User (siehe Link oben).
TK1987
TK1987 24.11.2022 um 11:34:20 Uhr
Goto Top
Zitat von @Crusher79:
Oder mit VBS und Hidden. Was besseres gibt es nicht oder?
Wie gesagt, einfach schnell eine Binary bauen, die den Code im Hintergrund ausführt.

Zum Beispiel so:
# Ausgabedatei
$Bin = "$HOME\Desktop\PsHiddenExec.exe"  

# Modul PS2EXE installieren
Install-Module -Scope CurrentUser PS2EXE -Confirm:$false

# Temporäre Skript-Datei erstellen
$TMP = "$ENV:Temp\PsHiddenExec.ps1"  
'iex ($args -join "`r`n")' | Set-Content -Encoding UTF8 -Path $TMP  

# Binärdatei erstellen
ps2exe -InputFile $TMP -Outputfile $Bin -NoConsole -NoOutput -NoError -NoVisualStyles
Am besten sollte die Binärdatei im Anschluss natürlich noch mit Set-AuthenticodeSignature signiert werden.

Dann einfach das Skript wie folgt starten:
PsHiddenExec.exe "&'C:\Pfad\zur\SkriptDatei.ps1'"  

Gruß Thomas
4400667902
Lösung 4400667902 24.11.2022 aktualisiert um 12:11:50 Uhr
Goto Top
Mittels Impersonation kann man auch aus einem geplanten Task der bspw. mit SYSTEM läuft heraus eine Meldung an den gerade angemeldeten User schicken ( so in etwa macht das auch die msg.exe), das geht bspw. so:
Zum Testen das ganze als geplanten Task und SYSTEM Rechten starten lassen, schon bekommt der gerade angemeldete User eine Msgbox zu Gesicht obwohl als geplanter Task mit SYSTEM gestartet.

Add-Type -ReferencedAssemblies 'System', 'System.Runtime.InteropServices' -TypeDefinition @'  
    using System;
    using System.Runtime.InteropServices;

    namespace Runasuser
    {
        public static class ProcessExtensions
        {
            #region Win32 Constants

            private const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
            private const int CREATE_NO_WINDOW = 0x08000000;

            private const int CREATE_NEW_CONSOLE = 0x00000010;

            private const uint INVALID_SESSION_ID = 0xFFFFFFFF;
            private static readonly IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;

            #endregion

            #region DllImports

            [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]  
            private static extern bool CreateProcessAsUser(
                IntPtr hToken,
                String lpApplicationName,
                String lpCommandLine,
                IntPtr lpProcessAttributes,
                IntPtr lpThreadAttributes,
                bool bInheritHandle,
                uint dwCreationFlags,
                IntPtr lpEnvironment,
                String lpCurrentDirectory,
                ref STARTUPINFO lpStartupInfo,
                out PROCESS_INFORMATION lpProcessInformation);

            [DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]  
            private static extern bool DuplicateTokenEx(
                IntPtr ExistingTokenHandle,
                uint dwDesiredAccess,
                IntPtr lpThreadAttributes,
                int TokenType,
                int ImpersonationLevel,
                ref IntPtr DuplicateTokenHandle);

            [DllImport("userenv.dll", SetLastError = true)]  
            private static extern bool CreateEnvironmentBlock(ref IntPtr lpEnvironment, IntPtr hToken, bool bInherit);

            [DllImport("userenv.dll", SetLastError = true)]  
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool DestroyEnvironmentBlock(IntPtr lpEnvironment);

            [DllImport("kernel32.dll", SetLastError = true)]  
            private static extern bool CloseHandle(IntPtr hSnapshot);

            [DllImport("kernel32.dll")]  
            private static extern uint WTSGetActiveConsoleSessionId();

            [DllImport("Wtsapi32.dll")]  
            private static extern uint WTSQueryUserToken(uint SessionId, ref IntPtr phToken);

            [DllImport("wtsapi32.dll", SetLastError = true)]  
            private static extern int WTSEnumerateSessions(
                IntPtr hServer,
                int Reserved,
                int Version,
                ref IntPtr ppSessionInfo,
                ref int pCount);

            #endregion

            #region Win32 Structs

            private enum SW
            {
                SW_HIDE = 0,
                SW_SHOWNORMAL = 1,
                SW_NORMAL = 1,
                SW_SHOWMINIMIZED = 2,
                SW_SHOWMAXIMIZED = 3,
                SW_MAXIMIZE = 3,
                SW_SHOWNOACTIVATE = 4,
                SW_SHOW = 5,
                SW_MINIMIZE = 6,
                SW_SHOWMINNOACTIVE = 7,
                SW_SHOWNA = 8,
                SW_RESTORE = 9,
                SW_SHOWDEFAULT = 10,
                SW_MAX = 10
            }

            private enum WTS_CONNECTSTATE_CLASS
            {
                WTSActive,
                WTSConnected,
                WTSConnectQuery,
                WTSShadow,
                WTSDisconnected,
                WTSIdle,
                WTSListen,
                WTSReset,
                WTSDown,
                WTSInit
            }

            [StructLayout(LayoutKind.Sequential)]
            private struct PROCESS_INFORMATION
            {
                public IntPtr hProcess;
                public IntPtr hThread;
                public uint dwProcessId;
                public uint dwThreadId;
            }

            private enum SECURITY_IMPERSONATION_LEVEL
            {
                SecurityAnonymous = 0,
                SecurityIdentification = 1,
                SecurityImpersonation = 2,
                SecurityDelegation = 3,
            }

            [StructLayout(LayoutKind.Sequential)]
            private struct STARTUPINFO
            {
                public int cb;
                public String lpReserved;
                public String lpDesktop;
                public String lpTitle;
                public uint dwX;
                public uint dwY;
                public uint dwXSize;
                public uint dwYSize;
                public uint dwXCountChars;
                public uint dwYCountChars;
                public uint dwFillAttribute;
                public uint dwFlags;
                public short wShowWindow;
                public short cbReserved2;
                public IntPtr lpReserved2;
                public IntPtr hStdInput;
                public IntPtr hStdOutput;
                public IntPtr hStdError;
            }

            private enum TOKEN_TYPE
            {
                TokenPrimary = 1,
                TokenImpersonation = 2
            }

            [StructLayout(LayoutKind.Sequential)]
            private struct WTS_SESSION_INFO
            {
                public readonly UInt32 SessionID;

                [MarshalAs(UnmanagedType.LPStr)]
                public readonly String pWinStationName;

                public readonly WTS_CONNECTSTATE_CLASS State;
            }

            #endregion

            // Gets the user token from the currently active session
            private static bool GetSessionUserToken(ref IntPtr phUserToken)
            {
                var bResult = false;
                var hImpersonationToken = IntPtr.Zero;
                var activeSessionId = INVALID_SESSION_ID;
                var pSessionInfo = IntPtr.Zero;
                var sessionCount = 0;

                // Get a handle to the user access token for the current active session.
                if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, ref pSessionInfo, ref sessionCount) != 0)
                {
                    var arrayElementSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
                    var current = pSessionInfo;

                    for (var i = 0; i < sessionCount; i++)
                    {
                        var si = (WTS_SESSION_INFO)Marshal.PtrToStructure((IntPtr)current, typeof(WTS_SESSION_INFO));
                        current += arrayElementSize;

                        if (si.State == WTS_CONNECTSTATE_CLASS.WTSActive)
                        {
                            activeSessionId = si.SessionID;
                        }
                    }
                }

                // If enumerating did not work, fall back to the old method
                if (activeSessionId == INVALID_SESSION_ID)
                {
                    activeSessionId = WTSGetActiveConsoleSessionId();
                }

                if (WTSQueryUserToken(activeSessionId, ref hImpersonationToken) != 0)
                {
                    // Convert the impersonation token to a primary token
                    bResult = DuplicateTokenEx(hImpersonationToken, 0, IntPtr.Zero,
                        (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, (int)TOKEN_TYPE.TokenPrimary,
                        ref phUserToken);

                    CloseHandle(hImpersonationToken);
                }

                return bResult;
            }

            public static bool StartProcessAsCurrentUser(string appPath, string cmdLine = null, string workDir = null, bool visible = true)
            {
                var hUserToken = IntPtr.Zero;
                var startInfo = new STARTUPINFO();
                var procInfo = new PROCESS_INFORMATION();
                var pEnv = IntPtr.Zero;
                int iResultOfCreateProcessAsUser;

                startInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO));

                try
                {
                    if (!GetSessionUserToken(ref hUserToken))
                    {
                        throw new Exception("StartProcessAsCurrentUser: GetSessionUserToken failed.");  
                    }

                    uint dwCreationFlags = CREATE_UNICODE_ENVIRONMENT | (uint)(visible ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW);
                    startInfo.wShowWindow = (short)(visible ? SW.SW_SHOW : SW.SW_HIDE);
                    startInfo.lpDesktop = "winsta0\\default";  

                    if (!CreateEnvironmentBlock(ref pEnv, hUserToken, false))
                    {
                        throw new Exception("StartProcessAsCurrentUser: CreateEnvironmentBlock failed.");  
                    }

                    if (!CreateProcessAsUser(hUserToken,
                        appPath, // Application Name
                        cmdLine, // Command Line
                        IntPtr.Zero,
                        IntPtr.Zero,
                        false,
                        dwCreationFlags,
                        pEnv,
                        workDir, // Working directory
                        ref startInfo,
                        out procInfo))
                    {
                        iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();
                        throw new Exception("StartProcessAsCurrentUser: CreateProcessAsUser failed.  Error Code -" + iResultOfCreateProcessAsUser);  
                    }

                    iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();
                }
                finally
                {
                    CloseHandle(hUserToken);
                    if (pEnv != IntPtr.Zero)
                    {
                        DestroyEnvironmentBlock(pEnv);
                    }
                    CloseHandle(procInfo.hThread);
                    CloseHandle(procInfo.hProcess);
                }

                return true;
            }

        }
    }
'@  

[Runasuser.ProcessExtensions]::StartProcessAsCurrentUser("C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"," -EP Bypass -C `"Add-Type -A System.Windows.Forms;[System.Windows.Forms.MessageBox]::Show('Das ist eine Nachricht!','Benachrichtigung',0,64)`"","C:\windows",$false)  
SPSman
SPSman 27.11.2022 um 12:15:08 Uhr
Goto Top
Zitat von @4400667902:

Mittels Impersonation kann man auch aus einem geplanten Task der bspw. mit SYSTEM läuft heraus eine Meldung an den gerade angemeldeten User schicken ( so in etwa macht das auch die msg.exe), das geht bspw. so:
Zum Testen das ganze als geplanten Task und SYSTEM Rechten starten lassen, schon bekommt der gerade angemeldete User eine Msgbox zu Gesicht obwohl als geplanter Task mit SYSTEM gestartet.

Add-Type -ReferencedAssemblies 'System', 'System.Runtime.InteropServices' -TypeDefinition @'  
    using System;
    using System.Runtime.InteropServices;

    namespace Runasuser
    {
        public static class ProcessExtensions
        {
            #region Win32 Constants

            private const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
            private const int CREATE_NO_WINDOW = 0x08000000;

            private const int CREATE_NEW_CONSOLE = 0x00000010;

            private const uint INVALID_SESSION_ID = 0xFFFFFFFF;
            private static readonly IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;

            #endregion

            #region DllImports

            [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]  
            private static extern bool CreateProcessAsUser(
                IntPtr hToken,
                String lpApplicationName,
                String lpCommandLine,
                IntPtr lpProcessAttributes,
                IntPtr lpThreadAttributes,
                bool bInheritHandle,
                uint dwCreationFlags,
                IntPtr lpEnvironment,
                String lpCurrentDirectory,
                ref STARTUPINFO lpStartupInfo,
                out PROCESS_INFORMATION lpProcessInformation);

            [DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]  
            private static extern bool DuplicateTokenEx(
                IntPtr ExistingTokenHandle,
                uint dwDesiredAccess,
                IntPtr lpThreadAttributes,
                int TokenType,
                int ImpersonationLevel,
                ref IntPtr DuplicateTokenHandle);

            [DllImport("userenv.dll", SetLastError = true)]  
            private static extern bool CreateEnvironmentBlock(ref IntPtr lpEnvironment, IntPtr hToken, bool bInherit);

            [DllImport("userenv.dll", SetLastError = true)]  
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool DestroyEnvironmentBlock(IntPtr lpEnvironment);

            [DllImport("kernel32.dll", SetLastError = true)]  
            private static extern bool CloseHandle(IntPtr hSnapshot);

            [DllImport("kernel32.dll")]  
            private static extern uint WTSGetActiveConsoleSessionId();

            [DllImport("Wtsapi32.dll")]  
            private static extern uint WTSQueryUserToken(uint SessionId, ref IntPtr phToken);

            [DllImport("wtsapi32.dll", SetLastError = true)]  
            private static extern int WTSEnumerateSessions(
                IntPtr hServer,
                int Reserved,
                int Version,
                ref IntPtr ppSessionInfo,
                ref int pCount);

            #endregion

            #region Win32 Structs

            private enum SW
            {
                SW_HIDE = 0,
                SW_SHOWNORMAL = 1,
                SW_NORMAL = 1,
                SW_SHOWMINIMIZED = 2,
                SW_SHOWMAXIMIZED = 3,
                SW_MAXIMIZE = 3,
                SW_SHOWNOACTIVATE = 4,
                SW_SHOW = 5,
                SW_MINIMIZE = 6,
                SW_SHOWMINNOACTIVE = 7,
                SW_SHOWNA = 8,
                SW_RESTORE = 9,
                SW_SHOWDEFAULT = 10,
                SW_MAX = 10
            }

            private enum WTS_CONNECTSTATE_CLASS
            {
                WTSActive,
                WTSConnected,
                WTSConnectQuery,
                WTSShadow,
                WTSDisconnected,
                WTSIdle,
                WTSListen,
                WTSReset,
                WTSDown,
                WTSInit
            }

            [StructLayout(LayoutKind.Sequential)]
            private struct PROCESS_INFORMATION
            {
                public IntPtr hProcess;
                public IntPtr hThread;
                public uint dwProcessId;
                public uint dwThreadId;
            }

            private enum SECURITY_IMPERSONATION_LEVEL
            {
                SecurityAnonymous = 0,
                SecurityIdentification = 1,
                SecurityImpersonation = 2,
                SecurityDelegation = 3,
            }

            [StructLayout(LayoutKind.Sequential)]
            private struct STARTUPINFO
            {
                public int cb;
                public String lpReserved;
                public String lpDesktop;
                public String lpTitle;
                public uint dwX;
                public uint dwY;
                public uint dwXSize;
                public uint dwYSize;
                public uint dwXCountChars;
                public uint dwYCountChars;
                public uint dwFillAttribute;
                public uint dwFlags;
                public short wShowWindow;
                public short cbReserved2;
                public IntPtr lpReserved2;
                public IntPtr hStdInput;
                public IntPtr hStdOutput;
                public IntPtr hStdError;
            }

            private enum TOKEN_TYPE
            {
                TokenPrimary = 1,
                TokenImpersonation = 2
            }

            [StructLayout(LayoutKind.Sequential)]
            private struct WTS_SESSION_INFO
            {
                public readonly UInt32 SessionID;

                [MarshalAs(UnmanagedType.LPStr)]
                public readonly String pWinStationName;

                public readonly WTS_CONNECTSTATE_CLASS State;
            }

            #endregion

            // Gets the user token from the currently active session
            private static bool GetSessionUserToken(ref IntPtr phUserToken)
            {
                var bResult = false;
                var hImpersonationToken = IntPtr.Zero;
                var activeSessionId = INVALID_SESSION_ID;
                var pSessionInfo = IntPtr.Zero;
                var sessionCount = 0;

                // Get a handle to the user access token for the current active session.
                if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, ref pSessionInfo, ref sessionCount) != 0)
                {
                    var arrayElementSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
                    var current = pSessionInfo;

                    for (var i = 0; i < sessionCount; i++)
                    {
                        var si = (WTS_SESSION_INFO)Marshal.PtrToStructure((IntPtr)current, typeof(WTS_SESSION_INFO));
                        current += arrayElementSize;

                        if (si.State == WTS_CONNECTSTATE_CLASS.WTSActive)
                        {
                            activeSessionId = si.SessionID;
                        }
                    }
                }

                // If enumerating did not work, fall back to the old method
                if (activeSessionId == INVALID_SESSION_ID)
                {
                    activeSessionId = WTSGetActiveConsoleSessionId();
                }

                if (WTSQueryUserToken(activeSessionId, ref hImpersonationToken) != 0)
                {
                    // Convert the impersonation token to a primary token
                    bResult = DuplicateTokenEx(hImpersonationToken, 0, IntPtr.Zero,
                        (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, (int)TOKEN_TYPE.TokenPrimary,
                        ref phUserToken);

                    CloseHandle(hImpersonationToken);
                }

                return bResult;
            }

            public static bool StartProcessAsCurrentUser(string appPath, string cmdLine = null, string workDir = null, bool visible = true)
            {
                var hUserToken = IntPtr.Zero;
                var startInfo = new STARTUPINFO();
                var procInfo = new PROCESS_INFORMATION();
                var pEnv = IntPtr.Zero;
                int iResultOfCreateProcessAsUser;

                startInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO));

                try
                {
                    if (!GetSessionUserToken(ref hUserToken))
                    {
                        throw new Exception("StartProcessAsCurrentUser: GetSessionUserToken failed.");  
                    }

                    uint dwCreationFlags = CREATE_UNICODE_ENVIRONMENT | (uint)(visible ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW);
                    startInfo.wShowWindow = (short)(visible ? SW.SW_SHOW : SW.SW_HIDE);
                    startInfo.lpDesktop = "winsta0\\default";  

                    if (!CreateEnvironmentBlock(ref pEnv, hUserToken, false))
                    {
                        throw new Exception("StartProcessAsCurrentUser: CreateEnvironmentBlock failed.");  
                    }

                    if (!CreateProcessAsUser(hUserToken,
                        appPath, // Application Name
                        cmdLine, // Command Line
                        IntPtr.Zero,
                        IntPtr.Zero,
                        false,
                        dwCreationFlags,
                        pEnv,
                        workDir, // Working directory
                        ref startInfo,
                        out procInfo))
                    {
                        iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();
                        throw new Exception("StartProcessAsCurrentUser: CreateProcessAsUser failed.  Error Code -" + iResultOfCreateProcessAsUser);  
                    }

                    iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();
                }
                finally
                {
                    CloseHandle(hUserToken);
                    if (pEnv != IntPtr.Zero)
                    {
                        DestroyEnvironmentBlock(pEnv);
                    }
                    CloseHandle(procInfo.hThread);
                    CloseHandle(procInfo.hProcess);
                }

                return true;
            }

        }
    }
'@  

[Runasuser.ProcessExtensions]::StartProcessAsCurrentUser("C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"," -EP Bypass -C `"Add-Type -A System.Windows.Forms;[System.Windows.Forms.MessageBox]::Show('Das ist eine Nachricht!','Benachrichtigung',0,64)`"","C:\windows",$false)  


Hi
Ich habe jetzt mal den Stumpf in die PS ISE reinkopiert, da kam allerdings:

Ausnahme beim Aufrufen von "StartProcessAsCurrentUser" mit 4 Argument(en): "StartProcessAsCurrentUser: GetSessionUserToken failed."
In Zeile:273 Zeichen:1
+ [Runasuser.ProcessExtensions]::StartProcessAsCurrentUser("C:\Windows\ ...

back-to-top~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : NotSpecified: (face-smile , MethodInvocationException
+ FullyQualifiedErrorId : Exception

Deine Idee gefällt mir allerdings habe ich scheinbar noch ein Verständnisproblem.
Kannst du mir vll. auf die Sprünge helfen?

@TK1987
Leider Kann ich mit dem Begriff Binary nix anfangen deshalb eher schwierig...
4400667902
4400667902 27.11.2022 aktualisiert um 12:20:25 Uhr
Goto Top
Ich habe jetzt mal den Stumpf in die PS ISE reinkopiert, da kam allerdings:
Das ist dein Fehler, das läuft dort nicht mit gleichem Account, das muss zwingend in der Ausführung in einem anderen Account-Kontext laufen,dann klappt's...
Also bspw. als geplanter Task mit SYSTEM als ausführender Account.
SPSman
SPSman 28.11.2022 um 21:57:24 Uhr
Goto Top
Zitat von @4400667902:

Ich habe jetzt mal den Stumpf in die PS ISE reinkopiert, da kam allerdings:
Das ist dein Fehler, das läuft dort nicht mit gleichem Account, das muss zwingend in der Ausführung in einem anderen Account-Kontext laufen,dann klappt's...
Also bspw. als geplanter Task mit SYSTEM als ausführender Account.

Nabend,

ich habe jetzt eine PS1 und Mittels " System Kontext ausgben lasen. hat super geklappt. Jetzt wollte ich es noch in eine Funktion Packen damit was allerding nicht Klappte weil es scheinbar mit der Variable nicht zurechtkommt:

$text_string= "Hallo_Welt"  
$text_string
[Runasuser.ProcessExtensions]::StartProcessAsCurrentUser("C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"," -EP Bypass -C `"Add-Type -A System.Windows.Forms;[System.Windows.Forms.MessageBox]::Show(`$text_string`,'Benachrichtigung',0,64)`"","C:\windows",$false)  

Habe ihr noch einen Tipp für mich?
4400667902
Lösung 4400667902 28.11.2022 aktualisiert um 22:52:38 Uhr
Goto Top
Variable falsch verwendet, die darf nicht escaped werden und muss in Hochkommas/Anführungszeichen.
$text_string = "Hallo_Welt"  
[Runasuser.ProcessExtensions]::StartProcessAsCurrentUser("C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"," -EP Bypass -C `"Add-Type -A System.Windows.Forms;[System.Windows.Forms.MessageBox]::Show('$text_string','Benachrichtigung',0,64)`"","C:\windows",$false)  
SPSman
SPSman 29.11.2022 um 10:21:54 Uhr
Goto Top
Hi,

das kappt jetzt!

allerdings kann "SYSTEM" nicht auf ein Netzlaufwerk zugreifen...
4400667902
4400667902 29.11.2022 aktualisiert um 10:24:09 Uhr
Goto Top
Zitat von @SPSman:
allerdings kann "SYSTEM" nicht auf ein Netzlaufwerk zugreifen...

Das ist Quatsch mit Soße, klar kann es das! Man muss nur den Machine Account auf dem Share berechtigen, bzw. eine Gruppe in dem der Computeraccount Mitglied ist z.B. die Gruppe "Domänen-Computer"!
SPSman
SPSman 29.11.2022 um 12:17:08 Uhr
Goto Top
Zitat von @4400667902:

Zitat von @SPSman:
allerdings kann "SYSTEM" nicht auf ein Netzlaufwerk zugreifen...

Das ist Quatsch mit Soße, klar kann es das! Man muss nur den Machine Account auf dem Share berechtigen, bzw. eine Gruppe in dem der Computeraccount Mitglied ist z.B. die Gruppe "Domänen-Computer"!

Ok ich habe mich ungenau ausgedrückt. in der Aktuellen Einstellung geht das nicht. Test-Path gib einen Fehler aus das das Netzlaufwerk nicht vorhanden ist.
Ein Zugriff von Computer-Konto auf das Share würde ich jetzt erstmal nicht freigeben wollen, der Security wegen...

Gibt es eine Option innerhalb des Scripts wo auf Ordner mit den Berechtigungen des aktuell angemeldeten Users zugegriffwird?

Danke.
4400667902
4400667902 29.11.2022 aktualisiert um 12:22:53 Uhr
Goto Top
Zitat von @SPSman:
Ok ich habe mich ungenau ausgedrückt. in der Aktuellen Einstellung geht das nicht. Test-Path gib einen Fehler aus das das Netzlaufwerk nicht vorhanden ist.
Normal wenn man keine UNC Pfade nutzt. Vorhandene Netzlaufwerke werden ausschließlich Account-Abhängig gemappt!!
Gibt es eine Option innerhalb des Scripts wo auf Ordner mit den Berechtigungen des aktuell angemeldeten Users zugegriffwird?
Zugriffe auf gemappte Netzlaufwerke des Users geht nur mit einem Registry-Eintrag
https://www.fmsinc.com/microsoftaccess/developer/mapped_drives_not_avail ...
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System]
"EnableLinkedConnections"=dword:00000001  
Ein Zugriff von Computer-Konto auf das Share würde ich jetzt erstmal nicht freigeben wollen, der Security wegen...
Normale User können damit eh nichts anfangen.
SPSman
SPSman 29.11.2022 aktualisiert um 12:41:57 Uhr
Goto Top
Zitat von @4400667902:

Zitat von @SPSman:
Ok ich habe mich ungenau ausgedrückt. in der Aktuellen Einstellung geht das nicht. Test-Path gib einen Fehler aus das das Netzlaufwerk nicht vorhanden ist.
Normal wenn man keine UNC Pfade nutzt. Vorhandene Netzlaufwerke werden ausschließlich Account-Abhängig gemappt!!
Gibt es eine Option innerhalb des Scripts wo auf Ordner mit den Berechtigungen des aktuell angemeldeten Users zugegriffwird?
Zugriffe auf gemappte Netzlaufwerke des Users geht nur mit einem Registry-Eintrag
https://www.fmsinc.com/microsoftaccess/developer/mapped_drives_not_avail ...
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System]
"EnableLinkedConnections"=dword:00000001  
Ein Zugriff von Computer-Konto auf das Share würde ich jetzt erstmal nicht freigeben wollen, der Security wegen...
Normale User können damit eh nichts anfangen.

Ok hab jetzt mit "Replace" den UNC-Pfad implementiert. Jetzt ist nur die Frage ob eine Freigabe für Domänen Computer nicht ein Sicherheitsrisikow darstell, dass wenn ein Lokales Konto auf den UNC Pfad zugreift, er durch dieses Tor ungewollt Zugriff erhält...

Mit UNC Pfad läuft mein Script händisch, aber nicht über den Aufgabenplaner(als SYSTEM)... :S
4400667902
4400667902 29.11.2022 aktualisiert um 12:51:26 Uhr
Goto Top
Zitat von @SPSman:
Jetzt ist nur die Frage ob eine Freigabe für Domänen Computer nicht ein Sicherheitsrisikow darstell, dass wenn ein Lokales Konto auf den UNC Pfad zugreift, er durch dieses Tor ungewollt Zugriff erhält...
Nein, der Prozess muss im Kontext von SYSTEM laufen, das kann ein normaler User nicht das können nur lokale Admins.
SPSman
SPSman 29.11.2022 aktualisiert um 13:04:34 Uhr
Goto Top
Zitat von @4400667902:

Zitat von @SPSman:
Jetzt ist nur die Frage ob eine Freigabe für Domänen Computer nicht ein Sicherheitsrisikow darstell, dass wenn ein Lokales Konto auf den UNC Pfad zugreift, er durch dieses Tor ungewollt Zugriff erhält...
Nein, der Prozess muss im Kontext von SYSTEM laufen, das kann ein normaler User nicht das können nur lokale Admins.

Es geht jetzt nicht um den Process "SENDE TEXT" sondern um die Share-Zugiffsberechtigung im allgemeinen.

Hier Mal die Scripts (Ein ToDo habe ich noch die Massage soll nach 60s wieder verschwinden):
#Aktuelle standardpfad Setzen
Set-Location "C:\01_Projekte"  

#dezidierte Scripte einbinden
Get-ChildItem ".\00_scripte" | Where {$_.Name -like "*.ps1"} | ForEach {  
 
    . .\00_scripte\$_
}

#Umlaute einschalten:
$OutputEncoding = [Console]::OutputEncoding = [Text.UTF8Encoding]::UTF8

$Zeilennummer = 1
If (Test-Connection pm2014 -Count 1 -quiet)
{
    $csvpath = '.\zap_Sync.CSV'  
    $Aufgaben = Import-Csv $csvpath -Delimiter ([regex]::match((gc $csvpath -Raw),'^("[^"]*"|[^,;]+)\s*([,;])').Groups[2].Value)  
    # Zeile der CSV durchgehen
    Foreach ($Aufgabe in $Aufgaben)
        {
        $Zielpfad=$Aufgabe.Ziel.Replace("P:","\\Server\Datenneu")  
        $Zeilennummer++
        # gültige Pfad in CSV eingetragen?
        If (!(Test-Path -Path $Aufgabe.Quelle))
            {
                
                $MsgText= "Quellpfad "+$Aufgabe.Quelle+" in CSV-Zeile "+$Zeilennummer+" nicht Vorhanden."  
                sendMassagetoUser($MsgText)
            }
        elseif (!(Test-Path -Path $Zielpfad))
            {
                
                $MsgText= "Zielpfad "+$Zielpfad+" in CSV-Zeile "+$Zeilennummer+" nicht Vorhanden."  
                sendMassagetoUser($toptext,$MsgText)
            }
        else
            {

            Write-Output ("Pfad "+$Zielpfad+"  gefunden")  
            $file = (Get-ChildItem $Aufgabe.Quelle -File -Recurse| Where {$_.Name -like "*.zap*"}| sort lastwritetime | select -last 1)  
            $ZielDatei= $Aufgabe.Ziel+"\"+"RW_"+$file.Name  
            #Zieldatei schon vorhanden?
            If (-NOT(Test-Path -Path $ZielDatei -PathType Leaf))
                {
                Write-Output ("Kopiere Datei "+$file.Name+" nach "+$ZielDatei)  
                Copy-Item $file.FullName -Destination $ZielDatei

                }
            }
            
        }
}#>

function sendMassagetoUser($text_string){

Add-Type -ReferencedAssemblies 'System', 'System.Runtime.InteropServices' -TypeDefinition @'  
    using System;
    using System.Runtime.InteropServices;

    namespace Runasuser
    {
        public static class ProcessExtensions
        {
            #region Win32 Constants

            private const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
            private const int CREATE_NO_WINDOW = 0x08000000;

            private const int CREATE_NEW_CONSOLE = 0x00000010;

            private const uint INVALID_SESSION_ID = 0xFFFFFFFF;
            private static readonly IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;

            #endregion

            #region DllImports

            [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]  
            private static extern bool CreateProcessAsUser(
                IntPtr hToken,
                String lpApplicationName,
                String lpCommandLine,
                IntPtr lpProcessAttributes,
                IntPtr lpThreadAttributes,
                bool bInheritHandle,
                uint dwCreationFlags,
                IntPtr lpEnvironment,
                String lpCurrentDirectory,
                ref STARTUPINFO lpStartupInfo,
                out PROCESS_INFORMATION lpProcessInformation);

            [DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]  
            private static extern bool DuplicateTokenEx(
                IntPtr ExistingTokenHandle,
                uint dwDesiredAccess,
                IntPtr lpThreadAttributes,
                int TokenType,
                int ImpersonationLevel,
                ref IntPtr DuplicateTokenHandle);

            [DllImport("userenv.dll", SetLastError = true)]  
            private static extern bool CreateEnvironmentBlock(ref IntPtr lpEnvironment, IntPtr hToken, bool bInherit);

            [DllImport("userenv.dll", SetLastError = true)]  
            [return: MarshalAs(UnmanagedType.Bool)]
            private static extern bool DestroyEnvironmentBlock(IntPtr lpEnvironment);

            [DllImport("kernel32.dll", SetLastError = true)]  
            private static extern bool CloseHandle(IntPtr hSnapshot);

            [DllImport("kernel32.dll")]  
            private static extern uint WTSGetActiveConsoleSessionId();

            [DllImport("Wtsapi32.dll")]  
            private static extern uint WTSQueryUserToken(uint SessionId, ref IntPtr phToken);

            [DllImport("wtsapi32.dll", SetLastError = true)]  
            private static extern int WTSEnumerateSessions(
                IntPtr hServer,
                int Reserved,
                int Version,
                ref IntPtr ppSessionInfo,
                ref int pCount);

            #endregion

            #region Win32 Structs

            private enum SW
            {
                SW_HIDE = 0,
                SW_SHOWNORMAL = 1,
                SW_NORMAL = 1,
                SW_SHOWMINIMIZED = 2,
                SW_SHOWMAXIMIZED = 3,
                SW_MAXIMIZE = 3,
                SW_SHOWNOACTIVATE = 4,
                SW_SHOW = 5,
                SW_MINIMIZE = 6,
                SW_SHOWMINNOACTIVE = 7,
                SW_SHOWNA = 8,
                SW_RESTORE = 9,
                SW_SHOWDEFAULT = 10,
                SW_MAX = 10
            }

            private enum WTS_CONNECTSTATE_CLASS
            {
                WTSActive,
                WTSConnected,
                WTSConnectQuery,
                WTSShadow,
                WTSDisconnected,
                WTSIdle,
                WTSListen,
                WTSReset,
                WTSDown,
                WTSInit
            }

            [StructLayout(LayoutKind.Sequential)]
            private struct PROCESS_INFORMATION
            {
                public IntPtr hProcess;
                public IntPtr hThread;
                public uint dwProcessId;
                public uint dwThreadId;
            }

            private enum SECURITY_IMPERSONATION_LEVEL
            {
                SecurityAnonymous = 0,
                SecurityIdentification = 1,
                SecurityImpersonation = 2,
                SecurityDelegation = 3,
            }

            [StructLayout(LayoutKind.Sequential)]
            private struct STARTUPINFO
            {
                public int cb;
                public String lpReserved;
                public String lpDesktop;
                public String lpTitle;
                public uint dwX;
                public uint dwY;
                public uint dwXSize;
                public uint dwYSize;
                public uint dwXCountChars;
                public uint dwYCountChars;
                public uint dwFillAttribute;
                public uint dwFlags;
                public short wShowWindow;
                public short cbReserved2;
                public IntPtr lpReserved2;
                public IntPtr hStdInput;
                public IntPtr hStdOutput;
                public IntPtr hStdError;
            }

            private enum TOKEN_TYPE
            {
                TokenPrimary = 1,
                TokenImpersonation = 2
            }

            [StructLayout(LayoutKind.Sequential)]
            private struct WTS_SESSION_INFO
            {
                public readonly UInt32 SessionID;

                [MarshalAs(UnmanagedType.LPStr)]
                public readonly String pWinStationName;

                public readonly WTS_CONNECTSTATE_CLASS State;
            }

            #endregion

            // Gets the user token from the currently active session
            private static bool GetSessionUserToken(ref IntPtr phUserToken)
            {
                var bResult = false;
                var hImpersonationToken = IntPtr.Zero;
                var activeSessionId = INVALID_SESSION_ID;
                var pSessionInfo = IntPtr.Zero;
                var sessionCount = 0;

                // Get a handle to the user access token for the current active session.
                if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, ref pSessionInfo, ref sessionCount) != 0)
                {
                    var arrayElementSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
                    var current = pSessionInfo;

                    for (var i = 0; i < sessionCount; i++)
                    {
                        var si = (WTS_SESSION_INFO)Marshal.PtrToStructure((IntPtr)current, typeof(WTS_SESSION_INFO));
                        current += arrayElementSize;

                        if (si.State == WTS_CONNECTSTATE_CLASS.WTSActive)
                        {
                            activeSessionId = si.SessionID;
                        }
                    }
                }

                // If enumerating did not work, fall back to the old method
                if (activeSessionId == INVALID_SESSION_ID)
                {
                    activeSessionId = WTSGetActiveConsoleSessionId();
                }

                if (WTSQueryUserToken(activeSessionId, ref hImpersonationToken) != 0)
                {
                    // Convert the impersonation token to a primary token
                    bResult = DuplicateTokenEx(hImpersonationToken, 0, IntPtr.Zero,
                        (int)SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, (int)TOKEN_TYPE.TokenPrimary,
                        ref phUserToken);

                    CloseHandle(hImpersonationToken);
                }

                return bResult;
            }

            public static bool StartProcessAsCurrentUser(string appPath, string cmdLine = null, string workDir = null, bool visible = true)
            {
                var hUserToken = IntPtr.Zero;
                var startInfo = new STARTUPINFO();
                var procInfo = new PROCESS_INFORMATION();
                var pEnv = IntPtr.Zero;
                int iResultOfCreateProcessAsUser;

                startInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO));

                try
                {
                    if (!GetSessionUserToken(ref hUserToken))
                    {
                        throw new Exception("StartProcessAsCurrentUser: GetSessionUserToken failed.");  
                    }

                    uint dwCreationFlags = CREATE_UNICODE_ENVIRONMENT | (uint)(visible ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW);
                    startInfo.wShowWindow = (short)(visible ? SW.SW_SHOW : SW.SW_HIDE);
                    startInfo.lpDesktop = "winsta0\\default";  

                    if (!CreateEnvironmentBlock(ref pEnv, hUserToken, false))
                    {
                        throw new Exception("StartProcessAsCurrentUser: CreateEnvironmentBlock failed.");  
                    }

                    if (!CreateProcessAsUser(hUserToken,
                        appPath, // Application Name
                        cmdLine, // Command Line
                        IntPtr.Zero,
                        IntPtr.Zero,
                        false,
                        dwCreationFlags,
                        pEnv,
                        workDir, // Working directory
                        ref startInfo,
                        out procInfo))
                    {
                        iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();
                        throw new Exception("StartProcessAsCurrentUser: CreateProcessAsUser failed.  Error Code -" + iResultOfCreateProcessAsUser);  
                    }

                    iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();
                }
                finally
                {
                    CloseHandle(hUserToken);
                    if (pEnv != IntPtr.Zero)
                    {
                        DestroyEnvironmentBlock(pEnv);
                    }
                    CloseHandle(procInfo.hThread);
                    CloseHandle(procInfo.hProcess);
                }

                return true;
            }

        }
    }
'@  



[Runasuser.ProcessExtensions]::StartProcessAsCurrentUser("C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"," -EP Bypass -C `"Add-Type -A System.Windows.Forms;[System.Windows.Forms.MessageBox]::Show('$text_string','Powershell Sync Tia',0,64)`"","C:\windows",$false)  
}
SPSman
SPSman 29.11.2022 um 13:06:20 Uhr
Goto Top
Kann ich der Funktion (letzte Zeile) nicht einfach eine "*.PS1" Datei mitgeben die dann im Userkontext des angemeldeten User läuft?
4400667902
4400667902 29.11.2022 aktualisiert um 13:28:56 Uhr
Goto Top
Kann ich der Funktion (letzte Zeile) nicht einfach eine "*.PS1" Datei mitgeben die dann im Userkontext des angemeldeten User läuft?
Sicher war ja nur ein Beispiel mit command ...

Ein ToDo habe ich noch die Massage soll nach 60s wieder verschwinden
Nimmst du statt der Messagebox einfach ein Popup, das kann das out of the box
(New-Object -Com Wscript.Shell).Popup("Das ist eine Nachricht",60,"Mein Titel",64)  

s geht jetzt nicht um den Process "SENDE TEXT" sondern um die Share-Zugiffsberechtigung im allgemeinen.
Um zuzugreifen müsste sich der User als SYSTEM ausgeben und das kann er nunmal nicht das können nur lokale Admins ...
SPSman
SPSman 01.12.2022 um 10:43:33 Uhr
Goto Top
Hallo,
Ich verstehe nicht warum "CSV-123" im Titel steht?
ps_popup

function sendMassage($Title,$text_string){
#################################################################
# Title of Message Window                                       #
$Title    #
#################################################################


##########################################################################################################################################################
# Body of Message Window
$body =$text_string+" `n`nBitte CSV prüfen."  
$body

###########################################################################################################################################################

#Display message box with Date/Time Accessed and Logged on User
$Shell = new-object -comobject wscript.shell -ErrorAction Stop
$Disclaimer = $Shell.popup("$body",30,"$Title",0)  

$Disclaimer | Out-Null
}

sendMassage("Achtung","CSV-123")  

Dankeschön nochmal
4400667902
4400667902 01.12.2022 aktualisiert um 11:19:45 Uhr
Goto Top
sendMassage("Achtung","CSV-123")
Weil du die Funktion falsch aufrufst ... In PowerShell werden keine Klammern und auch keine Kommas zur Trennung der Parameter in einem Funktionsaufruf verwendet ! Also bitte erst mal die Grundlagen "einmassieren".

sendMassage "Achtung" "CSV-123"  

Und massieren tut die Funktion auch nicht 😂😂😂, wäre aber schön wenn sie es bei mir täte ...🤪
SPSman
Lösung SPSman 13.12.2022 um 08:38:45 Uhr
Goto Top
Hi,

hier jetzt mein Endresultat:

Ich habe mir eine ".bat" gebastelt die Powershell im minimierten Zustand aufruft:
start /min powershell -file C:\Projekte\Sync_Zap.ps1


Das PS-Script ist dann eher Einfach:

#Aktuelle standardpfad Setzen
Set-Location "C:\01_Projekte"  

#dezidierte Scripte einbinden
Get-ChildItem ".\00_scripte" | Where {$_.Name -like "*.ps1"} | ForEach {  
 
    . .\00_scripte\$_
}

$Zeilennummer = 1
If (Test-Connection Server22 -Count 1 -quiet)
{
    $csvpath = '.\zap_Sync.CSV'  
    $Aufgaben = Import-Csv $csvpath -Delimiter ([regex]::match((gc $csvpath -Raw),'^("[^"]*"|[^,;]+)\s*([,;])').Groups[2].Value)  
    $toptext= "Meldung Powershell .zap*-Sychronisation"  
    # Zeile der CSV durchgehen
    Foreach ($Aufgabe in $Aufgaben)
        {
        $Zielpfad=$Aufgabe.Ziel.Replace("P:","\\Server22")  
        $Zeilennummer++
        # gültige Pfad in CSV eingetragen?
        If (!(Test-Path -Path $Aufgabe.Quelle))
            {
                
                $MsgText= "Quellpfad "+$Aufgabe.Quelle+" in CSV-Zeile "+$Zeilennummer+" nicht Vorhanden."  
                sendenachricht $toptext $MsgText 
            }
        elseif (!(Test-Path -Path $Zielpfad))
            {
                
                $MsgText= "Zielpfad "+$Zielpfad+" in CSV-Zeile "+$Zeilennummer+" nicht Vorhanden."  
                sendenachricht $toptext $MsgText 
            }
        else
            {

            Write-Output ("Pfad "+$Zielpfad+"  gefunden")  
# aktuellste zap-Datei suchen
            $file = (Get-ChildItem $Aufgabe.Quelle -File -Recurse| Where {$_.Name -like "*.zap*"}| sort lastwritetime | select -last 1)  
#Dateipräfix einbinden
            $ZielDatei= $Aufgabe.Ziel+"\"+"TestUser_"+$file.Name  
            #Zieldatei schon vorhanden?
            If (-NOT(Test-Path -Path $ZielDatei -PathType Leaf))
                {
                Write-Output ("Kopiere Datei "+$file.Name+"\r nach "+$ZielDatei)  
                Copy-Item $file.FullName -Destination $ZielDatei

                }
            }
            
        }

und noch das Sende Nachricht Modul:
function sendenachricht($Title,$text_string){
#################################################################
# Title of Message Window                                       
$Title    
#################################################################

#################################################################
# Body of Message Window
$body =$text_string+" `n`nBitte CSV prüfen."  
$body
#################################################################

#Display message box 
$Shell = new-object -comobject wscript.shell -ErrorAction Stop
$Disclaimer = $Shell.popup("`n$body",15,"$Title",64)  

$Disclaimer | Out-Null
}

Ich Überlege noch ein kleines TUT zu machen für die Community, oder ist das Projekt zu trivial? ^.-
SPSman
SPSman 15.12.2022 aktualisiert um 09:22:19 Uhr
Goto Top
Guten Morgen nochmal,

ich habe jetzt weiter optimiert, sodass ich das PS-Script 1 (siehe letzter Post) wieder im Userkontext System laufen lasse.
Allerdings sagt er das er den Netzwerk Pfad trotz Nutzung das UNC Pfades nicht finden kann... (Zeile 28:
...
elseif (!(Test-Path -Path $Zielpfad))
...

Ich bitte nochmals um ein Tipp.