@@ -14,6 +14,28 @@ $asciiArt = @"
1414
1515"@
1616
17+ # Enable long path support
18+ function Enable-LongPaths {
19+ Write-Host " Enabling long path support..."
20+ Set-ItemProperty - Path " HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" - Name " LongPathsEnabled" - Value 1
21+ }
22+
23+ Enable-LongPaths
24+
25+ # Add Windows API DeleteFile and MoveFile functions
26+ Add-Type - TypeDefinition @"
27+ using System;
28+ using System.Runtime.InteropServices;
29+ public class WinAPI {
30+ [DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)]
31+ [return: MarshalAs(UnmanagedType.Bool)]
32+ public static extern bool DeleteFile(string path);
33+
34+ [DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)]
35+ public static extern bool MoveFile(string lpExistingFileName, string lpNewFileName);
36+ }
37+ "@
38+
1739# Define symbolic link creation function
1840function New-SymbolicLink {
1941 param (
@@ -23,13 +45,19 @@ function New-SymbolicLink {
2345 New-Item - Path $Path - ItemType SymbolicLink - Value $Target - Force
2446}
2547
26- # Define symbolic link removal function
48+ # Define symbolic link removal function using Windows API
2749function Remove-SymbolicLink {
2850 param (
2951 [string ]$Path
3052 )
3153 if ((Test-Path - Path $Path ) -and ((Get-Item - Path $Path ).Attributes -band [System.IO.FileAttributes ]::ReparsePoint)) {
32- Remove-Item - Path $Path - Force
54+ $result = [WinAPI ]::DeleteFile($Path )
55+ if ($result ) {
56+ Write-Host " Successfully removed symbolic link: $Path "
57+ } else {
58+ $errorMessage = [System.ComponentModel.Win32Exception ]::new([System.Runtime.InteropServices.Marshal ]::GetLastWin32Error()).Message
59+ Write-Host " Failed to remove symbolic link: $errorMessage "
60+ }
3361 }
3462}
3563
@@ -47,6 +75,23 @@ function Remove-EmptyDirectories {
4775 }
4876}
4977
78+ # Define a function to move files using the Windows API
79+ function Move-File-With-Metadata {
80+ param (
81+ [string ]$SourcePath ,
82+ [string ]$DestinationPath
83+ )
84+
85+ if ([WinAPI ]::MoveFile($SourcePath , $DestinationPath )) {
86+ Write-Host " Successfully moved $SourcePath to $DestinationPath with metadata updates."
87+ return $true
88+ } else {
89+ $errorMessage = [System.ComponentModel.Win32Exception ]::new([System.Runtime.InteropServices.Marshal ]::GetLastWin32Error()).Message
90+ Write-Host " Failed to move file: $errorMessage "
91+ return $false
92+ }
93+ }
94+
5095# Define mod installation function
5196function Install-Mod {
5297 param (
@@ -69,23 +114,23 @@ function Install-Mod {
69114 [string ]$TargetPath
70115 )
71116
72- Get-ChildItem - Path $SourcePath - Recurse - File | ForEach-Object {
117+ Get-ChildItem - LiteralPath $SourcePath - Recurse - File | ForEach-Object {
73118 $relativePath = $_.FullName.Substring ($SourcePath.Length ).TrimStart(" \" )
74119 $targetFilePath = Join-Path - Path $TargetPath - ChildPath $relativePath
75120 $backupFilePath = Join-Path - Path $backupDir - ChildPath $relativePath
76121
77- if (Test-Path - Path $targetFilePath ) {
122+ if (Test-Path - LiteralPath $targetFilePath ) {
78123 $backupNeeded = $true
79124
80125 # Create necessary directories in backup path
81- $backupDirPath = Split- Path - Path $backupFilePath - Parent
82- if (-not (Test-Path - Path $backupDirPath )) {
126+ $backupDirPath = [ System.IO. Path]::GetDirectoryName( $backupFilePath )
127+ if (-not (Test-Path - LiteralPath $backupDirPath )) {
83128 New-Item - ItemType Directory - Path $backupDirPath - Force
84129 }
85130
86131 # If target is a symbolic link, prompt the user for action
87- if ((Get-Item - Path $targetFilePath ).Attributes -band [System.IO.FileAttributes ]::ReparsePoint) {
88- $currentTarget = (Get-Item - Path $targetFilePath ).Target
132+ if ((Get-Item - LiteralPath $targetFilePath ).Attributes -band [System.IO.FileAttributes ]::ReparsePoint) {
133+ $currentTarget = (Get-Item - LiteralPath $targetFilePath ).Target
89134 Write-Host " Conflict: $targetFilePath is already linked to $currentTarget "
90135 $choice = Read-Host " Do you want to replace the existing link? (Enter 'yes' to replace or 'no' to keep the existing link) [default: yes]"
91136 if ($choice -eq ' no' -or $choice -eq ' n' ) {
@@ -94,14 +139,22 @@ function Install-Mod {
94139 }
95140
96141 # Backup the existing file
97- Copy-Item - Path $targetFilePath - Destination $backupFilePath - Force
98- # Remove the existing file
99- Remove-Item - Path $targetFilePath - Force
142+ $moveSuccess = Move-File - With- Metadata - SourcePath $targetFilePath - DestinationPath $backupFilePath
143+ if ($moveSuccess ) {
144+ Write-Host " File moved successfully: $targetFilePath "
145+ } else {
146+ Write-Host " Failed to move file: $targetFilePath "
147+ }
148+
149+ # Remove the existing file if it was successfully moved
150+ if (Test-Path - LiteralPath $targetFilePath ) {
151+ Remove-Item - LiteralPath $targetFilePath - Force
152+ }
100153 }
101154
102155 # Create necessary directories in target path
103- $targetDir = Split- Path - Path $targetFilePath - Parent
104- if (-not (Test-Path - Path $targetDir )) {
156+ $targetDir = [ System.IO. Path]::GetDirectoryName( $targetFilePath )
157+ if (-not (Test-Path - LiteralPath $targetDir )) {
105158 New-Item - ItemType Directory - Path $targetDir - Force
106159 }
107160
@@ -115,7 +168,7 @@ function Install-Mod {
115168 Copy-And - Link - SourcePath $ModSourcePath - TargetPath $GameDirectory
116169
117170 # Create the backup directory if needed
118- if ($backupNeeded -and -not (Test-Path - Path $backupDir )) {
171+ if ($backupNeeded -and -not (Test-Path - LiteralPath $backupDir )) {
119172 New-Item - ItemType Directory - Path $backupDir
120173 }
121174
@@ -135,22 +188,22 @@ function Uninstall-Mod {
135188 $backupDir = Join-Path - Path $BackupDirectory - ChildPath (" Backup-" + $ModName )
136189
137190 # Restore backup if it exists
138- if (Test-Path - Path $backupDir ) {
139- Get-ChildItem - Path $backupDir - Recurse - File | ForEach-Object {
191+ if (Test-Path - LiteralPath $backupDir ) {
192+ Get-ChildItem - LiteralPath $backupDir - Recurse - File | ForEach-Object {
140193 $relativePath = $_.FullName.Substring ($backupDir.Length ).TrimStart(" \" )
141194 $targetFilePath = Join-Path - Path $GameDirectory - ChildPath $relativePath
142195
143196 # Remove the symbolic link if it exists
144197 Remove-SymbolicLink - Path $targetFilePath
145198
146199 # Create necessary directories in target path
147- $targetDir = Split- Path - Path $targetFilePath - Parent
148- if (-not (Test-Path - Path $targetDir )) {
200+ $targetDir = [ System.IO. Path]::GetDirectoryName( $targetFilePath )
201+ if (-not (Test-Path - LiteralPath $targetDir )) {
149202 New-Item - ItemType Directory - Path $targetDir - Force
150203 }
151204
152205 # Restore the backup file
153- Copy-Item - Path $_.FullName - Destination $targetFilePath - Force
206+ Copy-Item - LiteralPath $_.FullName - Destination $targetFilePath - Force
154207 Write-Host " Restored: $targetFilePath "
155208 }
156209
@@ -160,7 +213,7 @@ function Uninstall-Mod {
160213 # No backup found, remove the symbolic links directly
161214 Write-Host " No backup found for mod: $ModName , removing symbolic links directly."
162215
163- Get-ChildItem - Path $ModSourcePath - Recurse - File | ForEach-Object {
216+ Get-ChildItem - LiteralPath $ModSourcePath - Recurse - File | ForEach-Object {
164217 $relativePath = $_.FullName.Substring ($ModSourcePath.Length ).TrimStart(" \" )
165218 $targetFilePath = Join-Path - Path $GameDirectory - ChildPath $relativePath
166219
@@ -180,7 +233,7 @@ function List-Mods {
180233 param (
181234 [string ]$GameDirectory
182235 )
183- Get-ChildItem - Path $GameDirectory - Recurse | Where-Object {
236+ Get-ChildItem - LiteralPath $GameDirectory - Recurse | Where-Object {
184237 $_.Attributes -band [System.IO.FileAttributes ]::ReparsePoint
185238 } | ForEach-Object {
186239 Write-Host $_.Name
@@ -193,8 +246,8 @@ function Read-Config {
193246 [string ]$ConfigFilePath
194247 )
195248 $config = @ {}
196- if (Test-Path - Path $ConfigFilePath ) {
197- Get-Content - Path $ConfigFilePath | ForEach-Object {
249+ if (Test-Path - LiteralPath $ConfigFilePath ) {
250+ Get-Content - LiteralPath $ConfigFilePath | ForEach-Object {
198251 $_ = $_.Trim ()
199252 if ($_.Length -gt 0 -and $_.Substring (0 , 1 ) -ne ' #' ) {
200253 $parts = $_ -split ' ='
@@ -217,7 +270,7 @@ function Select-Game {
217270 Clear-Host
218271 Write-Host $asciiArt - ForegroundColor Blue
219272 $gamesPath = Join-Path - Path $BasePath - ChildPath ' Games'
220- $games = Get-ChildItem - Path $gamesPath - Directory
273+ $games = Get-ChildItem - LiteralPath $gamesPath - Directory
221274
222275 Write-Host " Available games:" - ForegroundColor Cyan
223276 for ($i = 0 ; $i -lt $games.Count ; $i ++ ) {
@@ -275,11 +328,11 @@ function Is-Mod-Installed {
275328 [string ]$GameDirectory
276329 )
277330
278- $sampleFile = Get-ChildItem - Path $ModPath - Recurse - File | Select-Object - First 1
331+ $sampleFile = Get-ChildItem - LiteralPath $ModPath - Recurse - File | Select-Object - First 1
279332 if ($sampleFile ) {
280333 $relativePath = $sampleFile.FullName.Substring ($ModPath.Length ).TrimStart(" \" )
281334 $linkPath = Join-Path - Path $GameDirectory - ChildPath $relativePath
282- return (Test-Path - Path $linkPath ) -and ((Get-Item - Path $linkPath ).Attributes -band [System.IO.FileAttributes ]::ReparsePoint)
335+ return (Test-Path - LiteralPath $linkPath ) -and ((Get-Item - LiteralPath $linkPath ).Attributes -band [System.IO.FileAttributes ]::ReparsePoint)
283336 }
284337 return $false
285338}
@@ -292,7 +345,7 @@ function Select-Mod {
292345 )
293346 Clear-Host
294347 Write-Host $asciiArt - ForegroundColor Blue
295- $mods = Get-ChildItem - Path $modParentPath - Directory | Where-Object { $_.Name -notmatch ' ^Backup-' }
348+ $mods = Get-ChildItem - LiteralPath $modParentPath - Directory | Where-Object { $_.Name -notmatch ' ^Backup-' }
296349 $modList = @ ()
297350
298351 foreach ($mod in $mods ) {
0 commit comments