#Requires -Version 5.1 param( [Parameter(Mandatory=$true)] [string]$Path ) $ErrorActionPreference = "Stop" Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing function Get-Config { $configPaths = @( "$env:APPDATA\FreigabeKontextmenue\config.json", "$env:ProgramData\FreigabeKontextmenue\config.json" ) foreach ($configPath in $configPaths) { if (Test-Path $configPath) { return Get-Content $configPath -Raw | ConvertFrom-Json } } throw "Konfiguration nicht gefunden. Bitte zuerst installieren!" } function Get-UNCPath { param([string]$LocalPath) $drive = Split-Path -Path $LocalPath -Qualifier $driveLetter = $drive.TrimEnd(':') $netUse = net use 2>$null | Where-Object { $_ -match "^\s*\w*\s+$driveLetter`:" } if ($netUse) { $parts = $netUse -split '\s+' foreach ($part in $parts) { if ($part -match '^\\\\') { $uncRoot = $part $relativePath = $LocalPath.Substring($drive.Length) return Join-Path $uncRoot $relativePath } } } $psDrive = Get-PSDrive -Name $driveLetter -ErrorAction SilentlyContinue if ($psDrive -and $psDrive.DisplayRoot) { $relativePath = $LocalPath.Substring($drive.Length) return Join-Path $psDrive.DisplayRoot $relativePath } $wmiDrive = Get-WmiObject -Class Win32_LogicalDisk -Filter "DeviceID='$drive'" -ErrorAction SilentlyContinue if ($wmiDrive -and $wmiDrive.ProviderName) { $relativePath = $LocalPath.Substring($drive.Length) return Join-Path $wmiDrive.ProviderName $relativePath } $computerName = $env:COMPUTERNAME $adminShare = "\\$computerName\$driveLetter`$" $relativePath = $LocalPath.Substring($drive.Length) return Join-Path $adminShare $relativePath } function Get-DomainUsers { $users = @() try { $searcher = [adsisearcher]"(&(objectCategory=person)(objectClass=user))" $searcher.PageSize = 1000 $searcher.PropertiesToLoad.AddRange(@("samaccountname", "displayname", "mail")) # NetBIOS-Domänennamen ermitteln $rootDSE = [ADSI]"LDAP://RootDSE" $domainDN = $rootDSE.defaultNamingContext $domainSearcher = [adsisearcher]"(&(objectClass=domain))" $domainSearcher.SearchRoot = [ADSI]"LDAP://$domainDN" $domainResult = $domainSearcher.FindOne() $netbiosDomain = $null # NetBIOS-Name aus Partitions holen $configDN = $rootDSE.configurationNamingContext $partSearcher = [adsisearcher]"(&(objectClass=crossRef)(nCName=$domainDN))" $partSearcher.SearchRoot = [ADSI]"LDAP://CN=Partitions,$configDN" $partResult = $partSearcher.FindOne() if ($partResult -and $partResult.Properties["netbiosname"]) { $netbiosDomain = $partResult.Properties["netbiosname"][0] } # Fallback: Aus USERDOMAIN if (-not $netbiosDomain) { $netbiosDomain = $env:USERDOMAIN } $results = $searcher.FindAll() foreach ($result in $results) { $samAccount = $result.Properties["samaccountname"][0] $displayName = if ($result.Properties["displayname"]) { $result.Properties["displayname"][0] } else { $samAccount } $qualifiedName = "$netbiosDomain\$samAccount" $users += [PSCustomObject]@{ SamAccountName = $samAccount DisplayName = $displayName FullName = "$displayName ($samAccount)" QualifiedName = $qualifiedName Domain = $netbiosDomain IsLocal = $false } } } catch { # Fallback auf lokale Benutzer (kein AD verfügbar) $localUsers = Get-LocalUser -ErrorAction SilentlyContinue | Where-Object { $_.Enabled } foreach ($user in $localUsers) { $users += [PSCustomObject]@{ SamAccountName = $user.Name DisplayName = if ($user.FullName) { $user.FullName } else { $user.Name } FullName = if ($user.FullName) { "$($user.FullName) ($($user.Name))" } else { $user.Name } QualifiedName = "$env:COMPUTERNAME\$($user.Name)" Domain = $env:COMPUTERNAME IsLocal = $true } } } return $users | Sort-Object DisplayName } function Show-UserSelectionDialog { param([array]$Users) $form = New-Object System.Windows.Forms.Form $form.Text = "Benutzer ausw$([char]0x00E4)hlen - Freigabe" $form.Size = New-Object System.Drawing.Size(450, 530) $form.StartPosition = "CenterScreen" $form.FormBorderStyle = "FixedDialog" $form.MaximizeBox = $false $lblSearch = New-Object System.Windows.Forms.Label $lblSearch.Text = "Suchen:" $lblSearch.Location = New-Object System.Drawing.Point(10, 15) $lblSearch.Size = New-Object System.Drawing.Size(50, 20) $form.Controls.Add($lblSearch) $txtSearch = New-Object System.Windows.Forms.TextBox $txtSearch.Location = New-Object System.Drawing.Point(65, 12) $txtSearch.Size = New-Object System.Drawing.Size(355, 20) $form.Controls.Add($txtSearch) $listBox = New-Object System.Windows.Forms.ListBox $listBox.Location = New-Object System.Drawing.Point(10, 45) $listBox.Size = New-Object System.Drawing.Size(410, 330) $listBox.Font = New-Object System.Drawing.Font("Segoe UI", 10) $form.Controls.Add($listBox) $script:allUsers = $Users foreach ($user in $Users) { $listBox.Items.Add($user.FullName) | Out-Null } $txtSearch.Add_TextChanged({ $searchText = $txtSearch.Text.ToLower() $listBox.Items.Clear() foreach ($user in $script:allUsers) { if ($user.FullName.ToLower().Contains($searchText) -or $user.SamAccountName.ToLower().Contains($searchText)) { $listBox.Items.Add($user.FullName) | Out-Null } } }) $chkFullPath = New-Object System.Windows.Forms.CheckBox $chkFullPath.Text = "Kompletten Pfad in Verkn$([char]0x00FC)pfungsname schreiben" $chkFullPath.Location = New-Object System.Drawing.Point(10, 385) $chkFullPath.Size = New-Object System.Drawing.Size(410, 25) $chkFullPath.Font = New-Object System.Drawing.Font("Segoe UI", 9) $form.Controls.Add($chkFullPath) $lblExample = New-Object System.Windows.Forms.Label $lblExample.Text = "(z.B. 'Mandanten - S - Schmidt - Lohn' statt nur 'Lohn')" $lblExample.Location = New-Object System.Drawing.Point(27, 408) $lblExample.Size = New-Object System.Drawing.Size(400, 20) $lblExample.ForeColor = [System.Drawing.Color]::Gray $lblExample.Font = New-Object System.Drawing.Font("Segoe UI", 8) $form.Controls.Add($lblExample) $okBtn = New-Object System.Windows.Forms.Button $okBtn.Text = "Freigeben" $okBtn.Location = New-Object System.Drawing.Point(240, 450) $okBtn.Size = New-Object System.Drawing.Size(85, 30) $okBtn.Enabled = $false $okBtn.DialogResult = [System.Windows.Forms.DialogResult]::OK $form.AcceptButton = $okBtn $form.Controls.Add($okBtn) $cancelBtn = New-Object System.Windows.Forms.Button $cancelBtn.Text = "Abbrechen" $cancelBtn.Location = New-Object System.Drawing.Point(335, 450) $cancelBtn.Size = New-Object System.Drawing.Size(85, 30) $cancelBtn.DialogResult = [System.Windows.Forms.DialogResult]::Cancel $form.CancelButton = $cancelBtn $form.Controls.Add($cancelBtn) $listBox.Add_SelectedIndexChanged({ $okBtn.Enabled = $listBox.SelectedIndex -ge 0 }) $listBox.Add_DoubleClick({ if ($listBox.SelectedIndex -ge 0) { $form.DialogResult = [System.Windows.Forms.DialogResult]::OK $form.Close() } }) $script:selectedUser = $null $script:useFullPath = $false if ($form.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK -and $listBox.SelectedIndex -ge 0) { $selectedText = $listBox.SelectedItem $script:selectedUser = $script:allUsers | Where-Object { $_.FullName -eq $selectedText } | Select-Object -First 1 $script:useFullPath = $chkFullPath.Checked } return @{ User = $script:selectedUser UseFullPath = $script:useFullPath } } function Add-FreigabePermission { param( [string]$TargetPath, [string]$QualifiedUserName ) try { $acl = Get-Acl -Path $TargetPath $rights = [System.Security.AccessControl.FileSystemRights]::FullControl $inheritance = [System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [System.Security.AccessControl.InheritanceFlags]::ObjectInherit $propagation = [System.Security.AccessControl.PropagationFlags]::None $type = [System.Security.AccessControl.AccessControlType]::Allow $rule = New-Object System.Security.AccessControl.FileSystemAccessRule($QualifiedUserName, $rights, $inheritance, $propagation, $type) $acl.AddAccessRule($rule) Set-Acl -Path $TargetPath -AclObject $acl return $true } catch { throw "Fehler beim Setzen der Berechtigungen: $_" } } function Create-Shortcut { param( [string]$TargetPath, [string]$ShortcutPath ) $shell = New-Object -ComObject WScript.Shell $shortcut = $shell.CreateShortcut($ShortcutPath) $shortcut.TargetPath = $TargetPath $shortcut.Save() [System.Runtime.Interopservices.Marshal]::ReleaseComObject($shell) | Out-Null } function Save-FreigabeInfo { param( [string]$TargetPath, [string]$UserName ) $metaDir = if (Test-Path "$env:ProgramData\FreigabeKontextmenue") { "$env:ProgramData\FreigabeKontextmenue\meta" } else { "$env:APPDATA\FreigabeKontextmenue\meta" } if (-not (Test-Path $metaDir)) { New-Item -Path $metaDir -ItemType Directory -Force | Out-Null } $pathHash = [System.BitConverter]::ToString([System.Security.Cryptography.MD5]::Create().ComputeHash([System.Text.Encoding]::UTF8.GetBytes($TargetPath))).Replace("-","") $metaFile = Join-Path $metaDir "$pathHash.json" $meta = @{ TargetPath = $TargetPath Users = @() } if (Test-Path $metaFile) { $existing = Get-Content $metaFile -Raw | ConvertFrom-Json $meta.Users = @($existing.Users) } if ($UserName -notin $meta.Users) { $meta.Users += $UserName } $meta | ConvertTo-Json | Set-Content -Path $metaFile -Encoding UTF8 } try { $config = Get-Config $basePath = $config.LinkBasePath if (-not (Test-Path $Path)) { throw "Der Pfad existiert nicht: $Path" } $users = Get-DomainUsers if ($users.Count -eq 0) { throw "Keine Benutzer gefunden!" } $dialogResult = Show-UserSelectionDialog -Users $users if (-not $dialogResult.User) { exit 0 } $selectedUser = $dialogResult.User $useFullPath = $dialogResult.UseFullPath $userName = $selectedUser.SamAccountName $userFolder = Join-Path $basePath $userName if (-not (Test-Path $userFolder)) { New-Item -Path $userFolder -ItemType Directory -Force | Out-Null } $uncPath = Get-UNCPath -LocalPath $Path # Verknuepfungsname erstellen if ($useFullPath) { # Kompletten Pfad verwenden: \\server\Mandanten\S\Schmidt\Lohn -> Mandanten - S - Schmidt - Lohn $pathForName = $uncPath # UNC-Prefix und Servernamen entfernen if ($pathForName -match '^\\\\[^\\]+\\(.+)$') { $pathForName = $Matches[1] } # Backslashes durch " - " ersetzen $itemName = $pathForName -replace '\\', ' - ' } else { $itemName = Split-Path -Path $Path -Leaf } # Ungueltige Zeichen fuer Dateinamen entfernen/ersetzen # Verboten in Windows-Dateinamen: \ / : * ? " < > | $itemName = $itemName -replace '[\\/:*?"<>|]', '_' $shortcutPath = Join-Path $userFolder "$itemName.lnk" $counter = 1 while (Test-Path $shortcutPath) { $baseName = $itemName $shortcutPath = Join-Path $userFolder "$baseName ($counter).lnk" $counter++ } Create-Shortcut -TargetPath $uncPath -ShortcutPath $shortcutPath Add-FreigabePermission -TargetPath $Path -QualifiedUserName $selectedUser.QualifiedName Save-FreigabeInfo -TargetPath $Path -UserName $selectedUser.QualifiedName [System.Windows.Forms.MessageBox]::Show( "Freigabe erfolgreich erstellt!`n`nBenutzer: $($selectedUser.DisplayName)`nVerkn$([char]0x00FC)pfung: $shortcutPath`nUNC-Pfad: $uncPath", "Freigabe erfolgreich", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information ) } catch { [System.Windows.Forms.MessageBox]::Show( "Fehler: $($_.Exception.Message)", "Fehler bei Freigabe", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Error ) exit 1 }