Public/New-LocalRepository.ps1
# Helper function to detect OneDrive paths function Test-OneDrivePath { [CmdletBinding()] param([string]$Path) try { # Normalize the path $normalizedPath = [System.IO.Path]::GetFullPath($Path) # Get OneDrive paths from registry $oneDriveRegKeys = @( "HKCU:\Software\Microsoft\OneDrive\Accounts\*", "HKCU:\Environment" ) $oneDrivePaths = @() # Get OneDrive folder paths from registry foreach ($regKey in $oneDriveRegKeys) { try { if ($regKey -eq "HKCU:\Environment") { # Check for OneDrive environment variable $oneDriveEnv = Get-ItemProperty -Path $regKey -Name "OneDrive" -ErrorAction SilentlyContinue if ($oneDriveEnv -and $oneDriveEnv.OneDrive) { $oneDrivePaths += $oneDriveEnv.OneDrive } } else { # Check OneDrive account registry entries $accounts = Get-ItemProperty -Path $regKey -ErrorAction SilentlyContinue foreach ($account in $accounts) { if ($account.UserFolder) { $oneDrivePaths += $account.UserFolder } } } } catch { # Continue if registry access fails continue } } # Also check common OneDrive locations $commonOneDrivePaths = @( "$env:USERPROFILE\OneDrive", "$env:USERPROFILE\OneDrive - Microsoft" ) $oneDrivePaths += $commonOneDrivePaths # Check if the path starts with any OneDrive path foreach ($oneDrivePath in ($oneDrivePaths | Where-Object { $_ })) { $normalizedOneDrivePath = [System.IO.Path]::GetFullPath($oneDrivePath) if ($normalizedPath.StartsWith($normalizedOneDrivePath, [System.StringComparison]::OrdinalIgnoreCase)) { return $true } } return $false } catch { Write-Verbose "Error detecting OneDrive path: $($_.Exception.Message)" return $false } } # Helper function to set OneDrive folder to Always Available Offline function Set-OneDriveAlwaysAvailable { [CmdletBinding()] param([string]$Path) try { Write-Host " [ONEDRIVE] Setting folder to Always Available Offline..." -ForegroundColor Gray # Use attrib command to set the folder to always be available offline # The +P attribute sets the folder to be pinned (always available offline) $attribResult = & attrib +P "$Path" /S /D 2>&1 if ($LASTEXITCODE -eq 0) { Write-Host " [OK] OneDrive folder set to Always Available Offline" -ForegroundColor Green } else { # Try alternative method using PowerShell and COM try { Write-Host " - Trying alternative method..." -ForegroundColor Gray # Use PowerShell to set the pinned state via file attributes $folder = Get-Item -Path $Path $folder.Attributes = $folder.Attributes -bor [System.IO.FileAttributes]::ReparsePoint Write-Host " [OK] OneDrive folder configured for offline availability" -ForegroundColor Green } catch { Write-Warning "Could not set OneDrive folder to Always Available Offline: $($_.Exception.Message)" Write-Host " - You can manually set this in File Explorer: Right-click folder → Always keep on this device" -ForegroundColor Gray } } } catch { Write-Warning "Failed to configure OneDrive offline availability: $($_.Exception.Message)" Write-Host " - You can manually set this in File Explorer: Right-click folder → Always keep on this device" -ForegroundColor Gray } } function New-LocalRepository { <# .SYNOPSIS Create and setup a local NuGet repository directory. .DESCRIPTION Creates a local repository directory structure for storing NuPkg files. Optionally initializes it with NuGet repository structure and copies packages from a source. .PARAMETER Path Path where the local repository should be created. Defaults to C:\LocalNuGetRepo. .PARAMETER RepoName Name for the PowerShell repository registration. Defaults to 'LocalNuGetRepo'. .PARAMETER SourcePath Optional source path containing NuPkg files to copy to the new repository. .PARAMETER Initialize Initialize the repository with proper NuGet structure using nuget.exe. .PARAMETER Force Force creation even if the directory already exists. .PARAMETER DisableOneDriveOffline Skip setting OneDrive folders to Always Available Offline even if OneDrive path is detected. .EXAMPLE New-LocalRepository Creates a basic repository at C:\LocalNuGetRepo and registers it as 'LocalNuGetRepo'. .EXAMPLE New-LocalRepository -Path "C:\MyRepo" -RepoName "MyCustomRepo" -SourcePath "C:\Packages" -Initialize Creates a repository, copies packages from source, initializes NuGet structure, and registers as 'MyCustomRepo'. .EXAMPLE New-LocalRepository -Path "C:\Users\User\OneDrive\MyRepo" -DisableOneDriveOffline Creates a repository in OneDrive but skips setting it to Always Available Offline. #> [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Position = 0)] [string]$Path = $script:DefaultRepositoryPath, [Parameter(Position = 1)] [string]$RepoName = "LocalNuGetRepo", [Parameter()] [ValidateScript({ if ($_ -and -not (Test-Path -Path $_ -PathType Container)) { throw "Source path '$_' does not exist or is not a directory." } $true })] [string]$SourcePath, [Parameter()] [switch]$Initialize, [Parameter()] [switch]$Force, [Parameter()] [switch]$DisableOneDriveOffline ) try { Write-Host "Creating local repository: $Path" -ForegroundColor Cyan # Detect if this is a OneDrive path $isOneDrivePath = Test-OneDrivePath -Path $Path if ($isOneDrivePath) { Write-Host " [DETECTED] OneDrive path detected" -ForegroundColor Yellow } # Check if directory exists if (Test-Path -Path $Path) { Write-Host " [EXISTS] Directory already exists, using existing directory" -ForegroundColor Yellow } else { if ($PSCmdlet.ShouldProcess($Path, "Create local repository directory")) { # Create the repository directory New-Item -Path $Path -ItemType Directory -Force | Out-Null Write-Host " [OK] Repository directory created" -ForegroundColor Green } } # Set OneDrive folder to Always Available Offline if detected if ($isOneDrivePath -and (Test-Path -Path $Path) -and -not $DisableOneDriveOffline) { if ($PSCmdlet.ShouldProcess($Path, "Set OneDrive folder to Always Available Offline")) { Set-OneDriveAlwaysAvailable -Path $Path } } elseif ($isOneDrivePath -and $DisableOneDriveOffline) { Write-Host " [SKIP] OneDrive offline setting disabled by parameter" -ForegroundColor Yellow } if ($PSCmdlet.ShouldProcess($Path, "Setup local repository")) { # Copy packages from source if specified if ($SourcePath) { Write-Host " [COPY] Copying packages from source..." -ForegroundColor Gray $sourcePackages = Get-ChildItem -Path $SourcePath -Filter "*.nupkg" -File if ($sourcePackages) { foreach ($package in $sourcePackages) { $destPath = Join-Path -Path $Path -ChildPath $package.Name Copy-Item -Path $package.FullName -Destination $destPath -Force Write-Host " - Copied: $($package.Name)" -ForegroundColor Gray } Write-Host " [OK] Copied $($sourcePackages.Count) packages" -ForegroundColor Green } else { Write-Warning "No NuPkg files found in source path: $SourcePath" } } # Initialize NuGet structure if requested if ($Initialize) { Write-Host " [INIT] Initializing NuGet repository structure..." -ForegroundColor Gray # Try to find nuget.exe $nugetPath = $null $nugetLocations = @( "nuget.exe", "C:\Program Files\NuGet\nuget.exe", "$env:ProgramFiles\Microsoft Visual Studio\*\*\Common7\IDE\CommonExtensions\Microsoft\NuGet\nuget.exe", "$env:LOCALAPPDATA\Microsoft\VisualStudio\*\Extensions\*\Tools\nuget.exe" ) foreach ($location in $nugetLocations) { $resolved = Get-Command $location -ErrorAction SilentlyContinue if ($resolved) { $nugetPath = $resolved.Source break } # Try wildcard resolution for VS paths $wildcard = Get-ChildItem $location -ErrorAction SilentlyContinue | Select-Object -First 1 if ($wildcard) { $nugetPath = $wildcard.FullName break } } if ($nugetPath) { Write-Host " - Found nuget.exe: $nugetPath" -ForegroundColor Gray # Initialize repository $initResult = & $nugetPath init $Path $Path 2>&1 if ($LASTEXITCODE -eq 0) { Write-Host " [OK] NuGet repository structure initialized" -ForegroundColor Green } else { Write-Warning "Failed to initialize NuGet structure: $initResult" } } else { Write-Warning "nuget.exe not found. Repository created without NuGet initialization." Write-Host " To initialize later, run: nuget init `"$Path`" `"$Path`"" -ForegroundColor Gray } } # Register as PowerShell repository Write-Host " [REGISTER] Registering as PowerShell repository..." -ForegroundColor Gray # Check if repository is already registered $existingRepo = Get-PSRepository -Name $RepoName -ErrorAction SilentlyContinue if ($existingRepo) { # Update existing repository Set-PSRepository -Name $RepoName -SourceLocation $Path -InstallationPolicy Trusted Write-Host " [OK] Updated existing PowerShell repository registration" -ForegroundColor Green } else { # Register new repository Register-PSRepository -Name $RepoName -SourceLocation $Path -InstallationPolicy Trusted Write-Host " [OK] Registered as PowerShell repository: $RepoName" -ForegroundColor Green } # Show summary $packageCount = (Get-ChildItem -Path $Path -Filter "*.nupkg" -File | Measure-Object).Count Write-Host "`n[SUCCESS] Local repository created successfully!" -ForegroundColor Green Write-Host " Path: $Path" -ForegroundColor White Write-Host " Packages: $packageCount" -ForegroundColor White if ($packageCount -gt 0) { Write-Host "`nTo install packages, run:" -ForegroundColor Cyan Write-Host " Install-ModuleFromLocalRepo -Path `"$Path`"" -ForegroundColor White } } } catch { Write-Error "Failed to create local repository: $($_.Exception.Message)" } } |