pf-file.ps1
function Get-PS_WorkingFolder { ( Get-Location -PSProvider 'FileSystem' ).Path } function Remove-PSPath_Prefix { process { if ( $_ ) { $_ -replace '.*::' } } } function Get-Path { [CmdletBinding()] Param( [Parameter(ValueFromPipeline=$true)] $path ) process { if ( $null -eq $path ) { return $path } if ( $path -is [ScriptBlock] ) { $result = Invoke-Command -ScriptBlock $path return $result | Get-Path } if ( $path -is [string] ) { return $path | Remove-PSPath_Prefix } if ( $path -is [System.IO.FileSystemInfo] ) { return $path.FullName | Remove-PSPath_Prefix } if ( $path -is [System.Management.Automation.PathInfo] ) { return $path.ProviderPath | Remove-PSPath_Prefix } if ( $path | Get-Member -Name 'Path' ) { return $path.Path | Remove-PSPath_Prefix } if ( $path | Get-Member -Name 'PSPath' ) { return $path.PSPath | Remove-PSPath_Prefix } if ( $path | Get-Member -Name 'DirectoryName' ) { return $path.DirectoryName | Remove-PSPath_Prefix } throw "Path cannot be extracted from '$path' " } } function Get-Path:::Test { $null | Get-Path | assert $null "c.ps1" | Get-Path | assert "c.ps1" { "c.ps1" } | Get-Path | assert "c.ps1" { $null } | Get-Path | assert $null Get-Path "c.ps1" | assert "c.ps1" Get-Path ([PSCustomObject]@{PsPath = 'Microsoft.PowerShell.Core\FileSystem::C:\backups'}) | assert 'C:\backups' } function Get-PathItem { [CmdletBinding()] Param( [Parameter(ValueFromPipeline=$true)] $path ) process { if ( ( -not $path ) -or ($path.PSPath)) { return $path } $path = $path | Get-Path $item = ( Get-Item -LiteralPath $path -Force ) if (-not $item) { $Name = Split-Path $path -Leaf $parent = Split-Path $path -Parent $item = Get-ChildItem -Path $parent | Where-Object { $_.Name -eq $Name } } $Item } } function Split-Path_Ex { param( [Parameter(ValueFromPipeline=$true)] $Path, [int]$Level = 1, [switch]$Parent, [switch]$Leaf ) begin { if ($Parent) { $Level = 1 } if ($Leaf) { $Level = -1 } } Process { [string]$result = $path | Get-Path if ($Level -lt 0) { $resultParts = $result.Split([string[]]@('\','/'), [System.StringSplitOptions]::None)[$Level..-1] return [string]::join([IO.Path]::DirectorySeparatorChar,$resultParts) } for( $currentParent = $Level; $currentParent -gt 0 -and $result; $currentParent--) { $result = Split-Path $result -Parent } return $result; } } function Split-Path_Ex:::Test { 'A\B\C' | Split-Path_Ex -Level -4 | Assert -eq 'A\B\C' 'A\B\C' | Split-Path_Ex -Level -3 | Assert -eq 'A\B\C' 'A\B\C' | Split-Path_Ex -Level -2 | Assert -eq 'B\C' 'A\B\C' | Split-Path_Ex -Level -1 | Assert -eq 'C' 'A\B\C' | Split-Path_Ex -Leaf | Assert -eq 'C' 'A\B\C' | Split-Path_Ex -Level 0 | Assert -eq 'A\B\C' 'A\B\C' | Split-Path_Ex -Parent | Assert -eq 'A\B' 'A\B\C' | Split-Path_Ex | Assert -eq 'A\B' 'A\B\C' | Split-Path_Ex -Level 2 | Assert -eq 'A' 'A\B\C' | Split-Path_Ex -Level 3 | Assert -eq '' 'A\B\C' | Split-Path_Ex -Level 4 | Assert -eq '' } function Get-Url_NoPort { param( [Parameter(ValueFromPipeline=$true)] $uri ) [Uri]$uriInternal = $uri $result = $uriInternal.Scheme + '://' + $uriInternal.Host return $result } function Get-Url_NoPort:::Test { Get-Url_NoPort -uri https://Portal-EMP-TST.eastriding.gov.uk:4401 | assert -eq https://Portal-EMP-TST.eastriding.gov.uk } function Update-Path_EnsureQuoted { [CmdletBinding()] Param( [Parameter(ValueFromPipeline=$true)] $path, [string[]]$PathBreakers = @(' ') ) process { [string]$path = $path | Get-Path if (-not $path) { return $path } if ( $path.StartsWith('"') -and $path.EndsWith('"') ) { return $path } if ($PathBreakers) { $breaksFound = $PathBreakers | ForEach-Object { $path.Contains($_) } if (-not $breaksFound) { return $path } } return $path | Update-String_Enclose '"' } } function Update-Path_EnsureQuoted:::Test { 'a b' | Update-Path_EnsureQuoted | assert -eq '"a b"' 'ab' | Update-Path_EnsureQuoted | assert -eq 'ab' } function Assert-FileExists { [CmdletBinding()] Param( [Parameter(ValueFromPipeline=$true)] $path ) begin { $missing = $() } process { $path = Get-Path $path if ($path -and -not (Test-Path -path $path)) { $missing += $path } } end { if ( -not $missing ) { return } $fileList = $missing -join "`n`t" throw [System.IO.FileNotFoundException] "File not found.`n`t $fileList" } } function Test-Path_Parent { param( [Parameter(ValueFromPipeline=$true)] $path, $parent ) [string]$current = Get-Path -path $path $pattern = Join-Path -Path $parent -ChildPath "*" $current -like $pattern } function Test-Path_Parent:::Test{ Test-Path_Parent -path 'c:\a\b\c' -parent 'c:\a\b' | should -BeTrue Test-Path_Parent -path 'c:\a\b\c' -parent 'c:\a\X' | should -BeFalse } function Get-Path_Ancestors { param( [Parameter(ValueFromPipeline=$true)] $path, [int]$MaxCount = [Int]::MaxValue, [int]$skipCount = 1 ) begin { $separators = [char[]]@('/','\') } process { [string]$current = Get-Path -path $path $next = $last = $current.Length while ( ( $last -gt 0 ) -and ( $MaxCount -gt 0 ) ) { $next = $current.LastIndexOfAny($separators,$last - 1) $result = $current.Substring(0,$last) if ($result.LastIndexOfAny($separators) -ne ($result.Length - 1) ) { if ($skipCount -gt 0) { $skipCount-- } else { $result $MaxCount-- } } $last = $next } } } function Get-Path_Ancestors:::Example { '\\srv\a\' | Get-Path_Ancestors | assert -eq @('\\srv') '\\srv\a\b\c\d' | Get-Path_Ancestors | assert -eq @('\\srv\a\b\c','\\srv\a\b','\\srv\a','\\srv') 'srv\a/b\c\d' | Get-Path_Ancestors | assert -eq @('srv\a/b\c','srv\a/b','srv\a','srv') } Function Compress-Name ($maxLength = 240) { begin { $fso = New-Object -ComObject Scripting.FileSystemObject } process { $path = Get-Path $_ if ( $path.length -lt $maxLength ) { return $path } $parents = $path | Get-Path_Ancestors $parentExists = $parents | Where-Object { Test-Path $_ } | Select-Object -First 1 $folder = $fso.GetFolder($parentExists) $newPath = $path | Update-Prefix -prefix $parentExists -replace $folder.ShortPath return $newPath } } function Compress-Name:::Example { # requires an real existing path $testFile = Get-ChildItem -path "C:\Windows\Microsoft.NET\assembly\GAC_MSIL" -filter *.* -Recurse -ErrorAction SilentlyContinue | Where-Object { $_.FullName.Length -gt 250 } | Sort-Object LastWriteTime | Select-Object -First 1 $longPath = $testFile.FullName $longPath $result = $longPath | Compress-Name -maxLength 50 $result.length } function Expand-Path_LocalDrives { begin { $pattern = '*:\' $Drives = Get-PSDrive -PSProvider FileSystem $localDrives = $Drives | Where-Object DisplayRoot -notLike '\\*' | Where-Object Root -Like $pattern } process { $current = $_ if (-not $current) { return } if ( $current.StartsWith($pattern) ) { $localDrives.Root | ForEach-Object { $current | Update-Prefix -prefix $pattern -replace $_ } } elseif ( $current.StartsWith('*:.\') ) { $localDrives | ForEach-Object { if ( $_.CurrentLocation ) { $_.Root + $_.CurrentLocation + '\' } else { $_.Root } } | ForEach-Object { $current | Update-Prefix -prefix '*:.\' -replace $_ } } else { $current } } } # Resolve-Path that do not generate an exception when the path is not found function Expand-Path { [CmdletBinding()] Param( [Parameter(ValueFromPipeline=$true)] $Path, [Switch]$AllVariables, $any = '*' ) begin { function Env($name) { $result = Get-Item -Path ('Env:' + $name) -ErrorAction SilentlyContinue if ($result.value) { return $result.value } return '$Env:' + $name } } process { $result = Get-Path $Path if ($AllVariables) { $result = $result | Update-String_Enclose '"' $result = Invoke-Expression $result } $result = $result | Expand-Path_LocalDrives $result = $result | Where-Object { Test-Path $_ } | Resolve-Path $result | Get-Path } } function Expand-Path:::Test{ ( $null | Expand-Path | Measure-Object ).Count -eq 0 | assert $env:TEMP | Expand-Path | assert $env:TEMP '*:\windows' | Expand-Path | Select-Object -First 1 | assert 'C:\windows' ( '*:.\' | Expand-Path | Measure-Object ).Count -gt 0 | assert ( '.\*\..\*' | Expand-Path | Measure-Object ).Count -gt 0 | assert '$($env:SystemRoot)\Sy$($any)\dr*s\*c\hosts' | Expand-Path -AllVariables ` | assert -eq 'C:\Windows\System32\drivers\etc\hosts' '$(Env("SystemRoot"))\Sy$($any)\dr*s\*c\hosts' | Expand-Path -AllVariables ` | assert -eq 'C:\Windows\System32\drivers\etc\hosts' } function Get-Path_LongestExistingParent { [CmdletBinding()] Param( [Parameter(ValueFromPipeline=$true)] $Path ) process { $path = Get-Path $Path while ( $Path -and -not ( Test-Path $Path ) ) { $Path = Split-Path $Path -Parent } return $Path } } function Get-Path_LongestExistingParent:::Test { Get-Path_LongestExistingParent -Path C:\Windows\System\XXX\YYY | assert -eq 'C:\Windows\System' Get-Path_LongestExistingParent -Path SSS:\Windows\System\XXX\YYY | assert -eq '' } function Get-FolderWithFiles { [CmdletBinding()] Param( [Parameter(ValueFromPipeline=$true)] $folder, $filter ) process{ $folder | Get-ChildItem -Recurse -Filter $filter | ForEach-Object { $_.DirectoryName } | Select-Object -Unique } } function Get-FolderWithFiles:::Example{ Get-FolderWithFiles -folder $folder -filter *.configuration.xml } function Find-InPath ([String[]]$toFindList, [String[]]$lookin, [switch]$required) { if (-not $lookin) { $lookin = @( $home, $env:ChocolateyInstall , ${env:ProgramFiles(x86)}, $env:ProgramFiles ) $paths = $env:Path.Split(';') $lookin = $paths + $lookin | Where-Object { $_ } | Select-Object -Unique } $lookin = $lookin | Expand-Path foreach($toFind in $toFindList) { if ($toFind) { $toFind = '\' + $toFind } $locations = $lookin | ForEach-Object { $_ + $toFind } | Where-Object { test-path $_ } | Select-Object -First 1 if ($locations) { return $locations } } if ($required -and -not $locations){ throw "Not found [$toFindList] " } } function Find-InPath:::Test { Find-InPath notepad.exe -lookin 'C:\Windows\system32' | assert 'C:\Windows\system32\notepad.exe' Find-InPath notepad.exe | assert 'C:\Windows\system32\notepad.exe' Find-InPath nothere.exe, notepad.exe | assert 'C:\Windows\system32\notepad.exe' } function Get-LastFile_ByName_InFolders { [CmdletBinding()] Param( [Parameter(ValueFromPipeline=$true)] $folder, $filter ) begin { $lastFile = @{} } process{ $folder = Get-Path $folder $files = Get-ChildItem -Path $folder -Filter $filter -Recurse foreach ($file in $files) { $lastFile[$file.Name] = $file.Fullname } } end { $lastFile.values | Sort-Object } } function Get-LastFile:::Example { $patches = Get-ChildItem -path c:\code\tbc-2\src\Deploy\Patches -Recurse -Filter *.patch -Directory $patches | Get-LastFile_ByName_InFolders -filter *.xsn $patches | Get-LastFile_ByName_InFolders -filter *.dll $patches | Get-LastFile_ByName_InFolders -filter *.wsp } function Resolve-Exe($cmd) { $cmdInfo = Get-Command $cmd -ErrorAction SilentlyContinue if ( $cmdInfo ) { if ( $cmdInfo.Source ) { $cmdInfo.Source } else { $candidatePathList = @() $candidatePathList += $env:Path.Split(';') $candidatePathList += "$env:windir\System32" $candidatePathList = $candidatePathList | Select-Object -Unique foreach ($candidatePath in $candidatePathList) { $result = "$candidatePath\$($cmdInfo.Name)" if (Test-Path($result)) { return $result } } } } } function Resolve-Exe:::Test { Resolve-Exe notepad | assert -eq "$env:windir\system32\notepad.exe" Resolve-Exe ping | assert -eq "$env:windir\system32\ping.exe" } function Find-App ([string]$toFind, [switch]$required) { $result = Resolve-Exe $toFind if ( $result ) { return $result #return get-item -LiteralPath $result -Force } if (-not $toFind.Contains(".")) { $toFind = "$toFind.exe" } try { # $lookin = @( $env:ChocolateyInstall , ${env:ProgramFiles(x86)}, $env:ProgramFiles, "$env:windir\System32" ) # $result = $lookin | Get-ChildItem -fi $toFind -re -ea SilentlyContinue | Select-Object -First 1 } catch { $err = $_ Write-Warning $err } if ($required -and -not $result) { throw "Not found [$toFind] " } return $result } function Find-App:::Example { Find-App notepad++ Find-App robocopy } function Find-Path_Up ([string]$filename, [string]$folder, [switch]$Required ) { if ( -not $folder ) { $folder = Split-Path ( Get-PSCallStack )[1].ScriptName -Parent } $folder = ( Resolve-Path $folder ).Path $found = $false while ( $folder ) { $result = "$folder\$filename"; $folder = Split-Path $folder -Parent; if ( Test-Path $result ) { $found = $true ( Resolve-Path $result ).Path } } if ($Required -and -not $found) { throw "File '$filename' is required but not found in '$folder' or any of its parents" } } function Find-Path_Up:::Example { $expected = 'C:\Windows\System32\PING.EXE' Find-Path_Up 'ping.*' -folder C:\Windows\System32 | assert -eq $expected Find-Path_Up 'ping.*' -folder C:\Windows\System32\drivers\etc | assert -eq $expected { Find-Path_Up 'ping.*' -folder C:\Windows -Required } | assert -throw "Required" } function Add-Path { Param( [string]$path, [Parameter(ValueFromPipeline=$true)] [string]$result, [string]$separator = ';', [switch]$append ) if (-not $result) { return $path } if (-not $path) { return $result } $splitted = $result.Split($separator) if ( $path -in $splitted ) { return $result } if ($append) { return $result + $separator + $path } return $path + $separator + $result } function Add-Path:::Test { "A;B" | Add-Path "x:\" | assert -eq 'x:\;A;B' "X:\;B" | Add-Path "x:\" | assert -eq 'x:\;B' "" | Add-Path "x:\" | assert -eq 'x:\' } function Get-ScriptPath ([switch]$parent, [switch]$rootScript ) { $allStack = Get-PSCallStack $CommonScriptFolder = split-path $allStack[0].ScriptName -Parent $stack = $allStack | skip-until { $_.ScriptName -notlike "$CommonScriptFolder*" } $frame = & { if ($rootScript) { $stack | Where-Object ScriptName | Select-Object -Last 1 } else { $stack | Select-Object -First 1 } } $result = if ( $frame.ScriptName ) { $frame.ScriptName } else { if ($psISE) { $psISE.CurrentFile.FullPath } else { ( ( Get-PS_WorkingFolder ) | Join-Path -ChildPath '\.' ) } } return & { if ($parent) { Split-Path $result -Parent } else { $result } } } function Find-Path_Up_Extended ([string]$filename, [int]$MaxResults = 1, [int]$MaxLevels = 32, [ref]$testedPaths) { begin { $levelCountDown = $MaxLevels $preTestedPaths = if ($testedPaths) { $testedPaths.Value } else { @() } } Process { $folder = Get-Path $_ while ( $folder -and ( $levelCountDown -gt 0 ) ) { $levelCountDown-- $result = "$folder\$filename" $folder = Split-Path $folder -Parent if ($result -in $preTestedPaths) { continue } if ( Test-Path $result ) { ( Resolve-Path $result ).Path $MaxResults--; if ( $MaxResults -eq 0 ) { return } } if ($testedPaths) { $testedPaths.Value += $result } } } } # $tested = @() # 'C:\GIT\abc3\Build.CI\Commit' | Find-Path_Up_Extended '*.ps1' -testedPaths ([ref]$tested) -MaxResuls 10 function Find-WalkUp ([string]$filename, [switch]$Required, [int]$MaxResults = 1, [int]$MaxLevels = 32 ` ,[string[]]$startLookingIn, [switch]$psWorkingFolder, [switch]$rootScript, [switch]$scriptFolder, [string[]]$finallyLookIn) { function CalculateLookIntoLocations {Find-WalkUp [string[]]$lookInto = $startLookingIn ?? @() if ($psWorkingFolder) { $lookInto += Get-PS_WorkingFolder } if ($rootScript) { $lookInto += Get-ScriptPath -parent -rootScript } if ($scriptFolder) { $lookInto += Get-ScriptPath -parent } if ($finallyLookIn) { $lookInto = $lookInto + $finallyLookIn } $lookInto = $lookInto | Select-Object -Unique return $lookInto } $lookInto = CalculateLookIntoLocations $testedPaths = @() $MaxLevels = [Math]::Max(0, $MaxLevels) if ( $MaxResults -lt 0 ) { return } $results = $lookInto | Find-Path_Up_Extended -filename $filename -testedPaths ([ref]$testedPaths) -MaxLevels $MaxLevels if (-not $results -and $Required) { $msg = "File '$filename' not found`nTested Paths:`n" + ( $testedPaths | Out-String ) throw [System.IO.FileNotFoundException] $msg } $results } # Find-WalkUp "BuildName.input.ps1" -scriptFolder # Find-WalkUp "bin" -scriptFolder # . ( Find-Script 'TFS.ps1' -Required ) # Ensure to enclose in parenthesis function Remove-FolderAsync { # Is faster to rename the folder and then remove it async Param ( [Parameter(ValueFromPipeline=$true)] $path ) process { $folder = Get-Path $path if ( Test-Path $folder ) { Write-Host "Removing '$folder'" $parentfolder = [System.IO.Path]::GetDirectoryName($folder) $foldername = [System.IO.Path]::GetFileName($folder) $newName = "$($foldername)_$( [Guid]::NewGuid() ).bak.tmp" Get-Item -LiteralPath $folder -Force | Rename-Item -NewName $newName $job = start-job -ScriptBlock { Remove-Item $args[0] -Recurse -Force } -ArgumentList "$parentfolder\$newName" Write-Verbose $job } } } function Expand-8_3_Path { [CmdletBinding()] Param( [Parameter(ValueFromPipeline=$true)] $path ) process { if ( ( -not $path ) -or ( -not $path.contains('~') ) ) { return $path } $result = Invoke-InLocation -path $path -script { ( Get-Location ).Path } return $result } } function Expand-8_3_Path:::Example { Expand-8_3_Path -path 'C:\Progra~1' } function New-Folder_EnsureExists { [CmdletBinding()] Param ( [Parameter(ValueFromPipeline=$true)] $folder, [switch]$PassThru, [switch]$New, [switch]$Parent ) process { if ( $Parent ) { $folder = Split-Path $folder -Parent } if ( $New ) { $folder | Remove-FolderAsync } if ( Test-Path $folder ) { if ($PassThru) { $result = Expand-8_3_Path -path $folder $result = Get-Item -LiteralPath $result -Force } } else { Write-Host "Creating '$folder'" $result = mkdir $folder } if ($PassThru) { $result } } } function New-Folder_EnsureExists:::Example { $testFolder = "$env:temp\PS\New-Folder_EnsureExists.Example" New-Folder_EnsureExists -folder $testFolder } function Get-Files_Ignore($path, $ignoreList) { $condition = @() foreach ($ignore in $ignoreList) { $condition += [ScriptBlock]::Create( { $_.FullName -notlike "*\$ignore\*" }.ToString().Replace('$ignore',$ignore) ) $condition += [ScriptBlock]::Create( { $_.FullName -notlike "*\$ignore" }.ToString().Replace('$ignore',$ignore) ) } $predicate = $condition | Join-Script '-and' {$true} Get-ChildItem -Path $path -Recurse -Directory | Where-Object $predicate } function Update-Path_ReplaceFileSpecialChars($replaceWith = '_') { begin { $specialChars = @('/', '\', ':', '~', '?', '*', '<', '>', '|') # '.' is not included as is valid for extensions and as additional separator } process { $result = $_ foreach ($char in $specialChars ) { $result = $result.Replace($char,$replaceWith) } return $result } } function Update-Path_ReplaceFileSpecialChars:::Test { 'c:\abc.txt' | Update-Path_ReplaceFileSpecialChars | assert 'c__abc.txt' } function Add-FilenameSuffix ($suffix) { begin { if ( $null -eq $suffix ) { $suffix = '' } } Process { $filename = $_ if ( [string]::IsNullOrWhiteSpace($filename) ) { return $filename + $suffix } $dir = [System.IO.Path]::GetDirectoryName($filename) if ($dir) { $dir += '\' } $ext = [System.IO.Path]::GetExtension($filename); $name = [System.IO.Path]::GetFileNameWithoutExtension($filename); return $dir + $name + $suffix + "$ext" } } function Add-FilenameSuffix:::Test { 'abc.txt', 'abc', ' ', '','c:\d2\d1\abc.xml' | Add-FilenameSuffix '.EXT' | assert 'abc.EXT.txt', 'abc.EXT', ' .EXT', '.EXT', 'c:\d2\d1\abc.EXT.xml' } function Get-ItemUse { [CmdletBinding()] Param( [Parameter(ValueFromPipeline=$true)] $path ) process { $path = Get-Path $path if (-not $path) { return } $path = Update-Path_EnsureQuoted -path $path $handle = Invoke-Exe handle -accepteula -u $path $itemUses = $handle | Get-Regex_Match -regex '(?<pname>.+)\s+pid:\s(?<ProcessId>\d+)\s+type:\s(?<type>\w+)\s+(?<user>\S+)\s+(?<handle>\w+):\s(?<file>.+)' $itemUses } } function Get-ProcessUsingItem { [CmdletBinding()] Param( [Parameter(ValueFromPipeline=$true)] $path ) process { $itemUses = Get-ItemUse -path $path Get-Process | Where-Object Id -In $itemUses.ProcessId } } function Get-ProcessUsingItem:::Example { $ErrorActionPreference = 'stop' $foldername = [Guid]::NewGuid().ToString() + ".txt" $file = "$env:TEMP\$foldername" Set-Content $file 'SOMETHING' $job = Start-Job -ScriptBlock { Write-Host $pid $lockedFile = [System.io.File]::Open($using:file, 'Open', 'Read', 'None') Read-Host 'Press ENTER to release file' $lockedFile.Close() } if (-not ( wait-until -condition { $job.State -eq 'Blocked' } ) ) { throw 'Failed' } $processUsingIt = Get-ProcessUsingItem -path $file # Expected Exceotion { Remove-Item $file -Force -Recurse } | assert -throw '*' $processUsingIt | Stop-Process -Force if (-not ( wait-until -condition { -not (Get-ProcessUsingItem -path $file) } ) ) { throw 'Failed' } #Should work Remove-Item $file -Force -Recurse Stop-Job $job } function Get-LastWriteTime_Max { [CmdletBinding()] Param( [Parameter(ValueFromPipeline=$true)] $path ) process { $path = Get-Path $path $path | Get-ChildItem -Recurse -File | Sort-Object -Property LastWriteTime -Descending | Select-Object -First 1 } } function Copy-File { [CmdletBinding()] Param( [Parameter(ValueFromPipeline=$true, Mandatory=$true)] $filePath, [string]$FolderFrom, [Parameter(Mandatory=$true)] [string]$FolderTo, [string]$tempSuffix = '.wip', [Switch]$PassThru ) process { $filePath = Get-Path $filePath if (-not $filePath ) { return } if (-not $FolderFrom) { $FolderFrom = Split-Path $filePath -Parent } $destinationFilePath = $filePath | Update-Prefix -prefix $FolderFrom -replace $FolderTo -Required $destinationFilePath = $destinationFilePath | Compress-Name $destinationFile = if (test-path $destinationFilePath) { get-item -LiteralPath $destinationFilePath -Force } else { $null } $filePath = $filePath | Compress-Name $file = Get-Item -LiteralPath $filePath -Force if (($null -eq $destinationFile) -or ($destinationFile.LastWriteTime -lt $file.LastWriteTime)) { $destinationFileName = Split-Path $destinationFilePath -Leaf $destinationFolderPath = Split-Path $destinationFilePath -Parent New-Folder_EnsureExists $destinationFolderPath $destinationFilePathTemp = $destinationFilePath if ($tempSuffix) { $destinationFilePathTemp += $tempSuffix } if ( test-path $destinationFilePath ) { Remove-Item $destinationFilePath -Force -Verbose } if ( test-path $destinationFilePathTemp ) { Remove-Item $destinationFilePathTemp -Force -Verbose } $newFile = Copy-item -Path $filePath -Destination $destinationFilePathTemp -Force -Verbose -PassThru if ($tempSuffix -and ($newFile | Test-Path)) { Rename-Item -Path $destinationFilePathTemp -NewName $destinationFileName -Verbose } if ($PassThru){ return $newFile } } } } function Copy-File:::Example { $srcFolder = "$env:TEMP\copy-file-test-src" $destFolder = "$env:TEMP\copy-file-test-dest" #Expand 8.3 name $srcFolder = New-Folder_EnsureExists $srcFolder -New -PassThru | Get-Path Set-Content -Path "$srcFolder\a.txt" 'aaaa' get-childitem $srcFolder -recurse -File | Copy-File -FolderFrom $srcFolder -FolderTo $destFolder } function Copy-Folder { param ( $FolderFrom, $FolderTo, $like = '*', [string]$notlike = [Guid]::NewGuid(), [Switch]$ReturnFiles ) $startTime = [System.Diagnostics.Stopwatch]::StartNew() $FolderFrom = Resolve-Path $FolderFrom | get-path New-Folder_EnsureExists $FolderTo $FolderTo = Resolve-Path $FolderTo | Get-Path $copiedFiles = Get-ChildItem $FolderFrom -Recurse -File -Force | Where-Object FullName -like $like | Where-Object FullName -notlike $notlike | Copy-File -FolderFrom $FolderFrom -FolderTo $FolderTo -PassThru $startTime.Stop() Write-Host "Copy-Folder Finished in '$($startTime.Elapsed)' from '$FolderFrom' to '$FolderTo' " if ($ReturnFiles) { $copiedFiles } else { return $FolderTo } } function Get-Item_Where_Mode { [CmdletBinding()] Param( [Parameter(ValueFromPipeline=$true)] $path, [switch]$Not, [switch]$Directory, [switch]$Archive, [switch]$Hidden, [switch]$NotContentIndexed, [switch]$ReadOnly, [switch]$Encrypted ) process { $path = Get-Path $path if ( -not $path ) { return } if ( -not ( test-path $path ) ) { return $false } $item = Get-Item -LiteralPath $path -Force $attr = ( $item.Attributes -split ', ' ) $result = ( ( -not ( $Directory.IsPresent ) -or ($attr -contains 'Directory') ) ` -and ( -not ( $Archive.IsPresent ) -or ($attr -contains 'Archive') ) ` -and ( -not ( $Hidden.IsPresent ) -or ($attr -contains 'Hidden') ) ` -and ( -not ( $NotContentIndexed.IsPresent ) -or ($attr -contains 'NotContentIndexed') ) ` -and ( -not ( $ReadOnly.IsPresent ) -or ($attr -contains 'ReadOnly') ) ` -and ( -not ( $Encrypted.IsPresent ) -or ($attr -contains 'Encrypted') ) ) if ($Not.IsPresent) { $result = -not $result} if ($result) { return $item } } } function Get-Item_Where_Mode:::Example { $i = Get-Item_Where_Mode -path C:\temp\test.txt -Archive $i.Mode $i.Attributes } function Test-File_Access { [CmdLetBinding()] param( [Parameter(Mandatory=$true, ValueFromPipeLine=$true)] $Path, [Switch]$Read, [Switch]$Write ) process { $path = Get-Path $path $mode = [System.IO.FileMode]::Open $access = if ($Read) { [System.IO.FileAccess]::Read } else { if ($Write) { [System.IO.FileAccess]::Write } else { [System.IO.FileAccess]::Read } } try { $fileStream = New-Object 'System.IO.FileStream' -ArgumentList $path, $mode, $access } catch [System.UnauthorizedAccessException] { return $false } finally { if ($fileStream) { $fileStream.Close() } } return $true } } function Get-FileNamePart_Max { [CmdLetBinding()] param( [Parameter(Mandatory=$true)] $filter, [Switch]$AsNumber, $Default = $null, [Parameter(Mandatory=$true, ValueFromPipeLine=$true)] $Path ) begin{ $last = $Default if ( $AsNumber -and ( $null -eq $last )) { $last = 0 } } process { $Path = Get-Path -path $Path $name = Split-Path $Path -Leaf $nameMatch = $name | Get-Like_Match -like $filter if ( $nameMatch ) { $current = $nameMatch.1 if ($AsNumber) { $current = [int]$current } if ( -not ( $last -gt $current ) ) { $last = $current } } } end{ $last } } function Get-FileNamePart_Max:::Test { @() | Get-FileNamePart_Max -filter 'file_(AAA)_(*)' | Assert -eq $null @() | Get-FileNamePart_Max -filter 'file_(AAA)_(*)' -AsNumber | Assert -eq 0 @('file_(AAA)_(001)','file_(AAA)_(003)') | Get-FileNamePart_Max -filter 'file_(AAA)_(*)' | Assert -eq '003' @('file_(AAA)_(003)','file_(AAA)_(001)') | Get-FileNamePart_Max -filter 'file_(AAA)_(*)' | Assert -eq '003' @('file_(AAA)_(003)','file_(AAA)_(001)') | Get-FileNamePart_Max -filter 'file_(AAA)_(*)' -AsNumber | Assert -eq 3 } function Compare-ByFolderAndFileName { Param( $lhs, $rhs ) [string]$lhsPath = Get-Path -path $lhs [string]$rhsPath = Get-Path -path $rhs [char[]]$separators = @('/','\',':','.') $lhsParts = $lhsPath.Split($separators) $rhsParts = $rhsPath.Split($separators) for($i = 0; $i -lt $lhsParts.Count; $i++) { if ( $i -ge $rhsParts.Count ) { return 1 } if ( $lhsParts[$i] -gt $rhsParts[$i] ) { return 1 } if ( $lhsParts[$i] -lt $rhsParts[$i] ) { return -1 } } if ( $i -eq $rhsParts.Count ) { return 0 } if ( $i -gt $rhsParts.Count ) { throw 'Assert : Unexpected condition reached' } return -1 } function Compare-ByFolderAndFileName:::Example { Compare-ByFolderAndFileName -lhs c:\a\b -rhs c:\a\b | assert -eq 0 Compare-ByFolderAndFileName -lhs c:\a\b -rhs c:\a\b\c | assert -eq -1 Compare-ByFolderAndFileName -lhs c:\a\b\c -rhs c:\a\b | assert -eq 1 Compare-ByFolderAndFileName -lhs c:\a\b\c.xml -rhs c:\a\b\c1.xml | assert -eq -1 } function Get-Ignore_Files { $extList = @('bak','csv','log','txt','tmp','lock','svn','git','Unencrypted.*') $ignoreContent = $extList | ForEach-Object { "*.$_" } $ignoreContent += '* - Copy.*' $ignoreContent += '* - Copy (*).*' $ignoreContent += '*.*_*_*_*_*.sitemap' $ignoreContent } function Get-Text_Filter { $textFilter = @('*.config', '*.txt', '*.md', '*.cs*', '*.*proj', '*.sln', '*.nuspec', '*.bgi','*.sitemap','*.browser', '*.cnf', '*.script*' '*.htm*', '*.xml', '*.json', '*.ini', '*.js', '*.css','*.p*1', '*.sql', '*.resx', '*.aspx','*.*html','*.asp','*.svc' '*.gitignore', '*.gitconfig', '*.gitattributes','*.gitmodules','*.bat', '*.cmd', '*.master', '*.config','*.asax','*.xml','*.xsd','*.ascx','*.rsd','*.rdl' ) $textFilter } function Invoke-InLocation { param ( [Parameter(ValueFromPipeline=$true)] $path, [ScriptBlock]$script ) $path = Get-Path $path if (-not $path) { . $script return } Push-Location $path $path = Resolve-Path $path | Get-Path $currentDirectory = [System.IO.Directory]::GetCurrentDirectory() try { [System.IO.Directory]::SetCurrentDirectory($path) Write-Host "Invoke-InLocation '$path'" . $script } finally { [System.IO.Directory]::SetCurrentDirectory($currentDirectory) Pop-Location Write-Host "Invoke-InLocation Reverted to '$currentDirectory'" } } function Get-WebFile ([Uri] $url, [string] $folder, [string] $file) { if ([string]::IsNullOrWhiteSpace($file)) { $file = split-path $url.AbsolutePath -Leaf } if (![string]::IsNullOrWhiteSpace($folder)) { $file = Join-Path $folder $file } if ( test-path $file ) { return $file; } New-Folder_EnsureExists -folder $folder # Invoke-WebRequest -Uri $url -OutFile $file -Verbose $web = new-object System.Net.WebClient $web.DownloadFile($url,$file) return $file } function Get-WebFile:::Test { $src = 'C:\tmp' $uri = [Uri]'http://vm-Portalla.Portal.root.local:8080/repository/download/OneTrunk512_Product_Build/latest.lastSuccessful/C360UpdatePackage.zip?guest=1' $file = Get-WebFile -url $uri -folder $src Write-Verbose $file } function Expand-ZipFile($file, $destination, $filter) { try { Add-Type -Assembly System.IO.Compression.FileSystem $archive = [System.IO.Compression.ZipFile]::OpenRead($file) $toUnzip = $archive.Entries | Where-Object FullName -Like $filter $toUnzip | ForEach-Object { $folder = Split-Path $_.Fullname -Parent $folder = Join-Path $destination $folder New-Folder_EnsureExists -folder $folder $fileDestination = Join-Path $folder $_.Name Write-Host "Extracting to '$fileDestination'" [System.IO.Compression.ZipFileExtensions]::ExtractToFile($_, $fileDestination, $true) } } finally { if ($archive) { $archive.Dispose() } } } function Expand-ZipFile:::Example { Expand-ZipFile -file $file -filter '*.dacpac' -destination 'c:\tmp\Core' } function Rename-Item_Replace { param ( [Parameter(ValueFromPipeline=$true)] $item, $currentValue, $newValue ) process { $newName = $item.Name.Replace($currentValue,$newValue) $newFullName = ( Split-Path $item.FullName -Parent ) + "\$newName" if ( ( $newFullName -ne $item.FullName ) -and ( test-path $newFullName ) ) { # Remove only when it does not have the same name to rename Remove-Item $newFullName -Force -Verbose -Recurse } if ( $item.Name -cne $newName ) { if ($item.Name -eq $newName) { $item = $item | Rename-Item -NewName ([Guid]::NewGuid()) -Verbose -Force -PassThru } $item | Rename-Item -NewName $newName -Verbose -Force } } } Function New-SymLink ($link, $target, [switch]$hard) { Remove-SymLink $link $directoryFlag = if (test-path -pathtype container $target) { " /d" } $hardlinkFlag = if ($hard) { " /H" } invoke-expression "cmd /c mklink $hardlinkFlag $directoryFlag '$link' '$target' " } Function Remove-SymLink ($link) { if (-not (test-path $link) ) { return } $removeCommand = if (test-path -pathtype container $link) { "rmdir" } else { "del" } invoke-expression "cmd /c $removeCommand '$link'" } function Copy-AsJob($Path, $Destination) { $jobName = "Copy-AsJob from '$Path' to '$Destination'" Write-Host $jobName $job = start-job -ArgumentList $PSBoundParameters -Name "$packageLabel-$jobName" -ScriptBlock { [HashTable]$copyArgs = $args[0] Copy-Folder -FolderFrom $copyArgs.Path -FolderTo $copyArgs.Destination #ROBOCOPY /E /xo /np $copyArgs.Path $copyArgs.Destination #Copy @copyArgs -Recurse -Force -Verbose - } return $job } |