Though I'm using it regularly I still consider it alpha because I haven't really put it through its paces. A few words on how it works...It searches for vault.exe and caches its location in a file called _vault.location in the same directory where the script lives. It assumes the vault client was installed under "program files". On subsequent calls it reads the _vault.location, checks that it's valid and re-locates it if not; otherwise it uses the cached path. It needs tested in 64 bit environment. It implements a method for adding missing files (similar to the detect files to add functionality from the client) but that too needs further testing as well. Most of the code below is for the detect files to add method. Use at your own risk
Code: Select all
[CmdletBinding()]
param (
[parameter(Mandatory=$false)]
[Alias("Host")]
[ValidateNotNullOrEmpty()]
[string]$sccHost="your host name here",
[parameter(Mandatory=$true)]
[Alias("User")]
[ValidateNotNullOrEmpty()]
[string]$sccUser,
[parameter(Mandatory=$true)]
[Alias("Password")]
[ValidateNotNullOrEmpty()]
[string]$sccPassword,
[parameter(Mandatory=$false)]
[Alias("Action")]
[ValidateNotNullOrEmpty()]
[string]$sccAction = "GET"
)
$ErrorActionPreference = "Stop"
function Test-64bit()
{
return ([IntPtr]::Size -eq 8)
}
function Get-ProgramFilesPath()
{
if (Test-64bit)
{
$item = Get-Item "Env:ProgramFiles(x86)"
}
else
{
$item = Get-Item "Env:ProgramFiles"
}
$item.Value
}
function Get-ScriptFolderPath
{
$Scope = 1
$Directory = $null
do
{
$Invocation = (Get-Variable MyInvocation -Scope $Scope).Value
if ($Invocation.MyCommand.Path)
{
$Directory = (Split-Path $Invocation.MyCommand.Path)
}
$Scope += 1
}
while($Invocation -ne $null -and $Directory -eq $null)
$Directory
}
function New-VaultClient([string]$sccHost, [string]$sccUser, [string]$sccPassword, [string]$sccRepository)
{
$scriptFolderPath = Get-ScriptFolderPath
$locationFilePath = Join-Path $ScriptFolderPath "_vault.location"
$logFilePath = Join-Path $ScriptFolderPath "_vault.log"
$exeFilePath = $null
if (Test-Path $locationFilePath)
{
$exeFilePath = Get-Content $locationFilePath
}
if ($exeFilePath -eq $null -or !(Test-Path $exeFilePath))
{
$programFilesPath = Get-ProgramFilesPath
Write-Host ("Looking for vault.exe under {0}." -f $programFilesPath)
$exeFilePath = $programFilesPath |
gci -Include "*.exe" -Recurse |
? { $_.Name -match "^vault.exe$" } |
% { $_.FullName } |
Select-Object -First 1
Set-Content $locationFilePath $exeFilePath
}
if (Test-Path $logFilePath)
{
Clear-Content $logFilePath -Force
}
New-Object PSObject |
Add-Member -PassThru -MemberType NoteProperty -Force -Name "_scriptFolderPath" -Value $scriptFolderPath |
Add-Member -PassThru -MemberType NoteProperty -Force -Name "_locationFilePath" -Value $locationFilePath |
Add-Member -PassThru -MemberType NoteProperty -Force -Name "_logFilePath" -Value $logFilePath |
Add-Member -PassThru -MemberType NoteProperty -Force -Name "Host" -Value $sccHost |
Add-Member -PassThru -MemberType NoteProperty -Force -Name "User" -Value $sccUser |
Add-Member -PassThru -MemberType NoteProperty -Force -Name "Password" -Value $sccPassword |
Add-Member -PassThru -MemberType NoteProperty -Force -Name "Repository" -Value $sccRepository |
Add-Member -PassThru -MemberType NoteProperty -Force -Name "Executable" -Value $exeFilePath |
Add-Member -PassThru -MemberType ScriptMethod -Force -Name "Execute" -Value {
param([string]$action, [object[]]$params)
$result = [xml](& $this.Executable $action -host $this.Host -user $this.User -password $this.Password -repository $this.Repository @params)
if ($result.SelectSingleNode("/vault/result/success/text()").Value -ne "True")
{
Write-Warning ("{0} failed with params {1}." -f $action, [string]::Join(" ", $params))
$exception = $result.SelectSingleNode("/vault/error/exception/text()")
if ($exception)
{
Write-Warning "Details about the failure have been logged."
Add-Content $this._logFilePath ($exception.Value + "`r`n`r`n")
}
}
$result
} |
Add-Member -PassThru -MemberType ScriptMethod -Force -Name "GetFolderDetails" -Value {
param([ValidateNotNullOrEmpty()][string]$sccPath)
$this.Execute("LISTFOLDER", @($sccPath))
} |
Add-Member -PassThru -MemberType ScriptMethod -Force -Name "GetLatest" -Value {
param([ValidateNotNullOrEmpty()][string]$sccPath)
$files = $this.GetFolderDetails($sccPath).SelectNodes("//file[@status]") |
% { Join-Path $_.SelectSingleNode("parent::folder/@workingfolder").Value $_.Name }
$this.Execute("GET", @("-performdeletions", "-verbose", $sccPath)) | Out-Null
$files
} |
Add-Member -PassThru -MemberType ScriptMethod -Force -Name "AddMissingFiles" -Value {
param([ValidateNotNullOrEmpty()][string]$sccPath)
$addedFolders = @()
$details = $this.GetFolderDetails($sccPath);
$details.SelectNodes("(//@workingfolder | //@name[parent::file])") |
% { $_.value = $_.value.ToUpper() }
$localFolder = $details.SelectSingleNode("/vault/folder/@workingfolder").Value
$remoteFiles = $details.SelectNodes("//file") |
% { Join-Path $_.SelectSingleNode("parent::folder/@workingfolder").Value $_.Name }
$localFiles = $localFolder |
gci -Recurse |
? { !$_.PSIsContainer } |
% {
@{
DirectoryName = $_.DirectoryName.ToUpper()
FullName = $_.FullName.ToUpper()
}
}
$localFiles |
? { $remoteFiles -notcontains $_.FullName } |
% {
$query = ("//folder[@workingfolder='{0}']" -f $_.DirectoryName)
$remoteFolder = $details.SelectSingleNode($query)
if ($remoteFolder)
{
$this.Execute("ADD", @("-commit", $remoteFolder.Name, $_.FullName)) | Out-Null
$_.FullName
}
else
{
# If this file's directory starts with the name of any
# directory already added then we can skip it.
$directoryName = $_.DirectoryName
if (-not ($addedFolders | ? { $directoryName.StartsWith($_)}))
{
while($remoteFolder -eq $null -and $directoryName -ne "")
{
$parentDirectoryName = Split-Path $directoryName
$query = ("//folder[@workingfolder='{0}']" -f $parentDirectoryName)
$remoteFolder = $details.SelectSingleNode($query)
if (!$remoteFolder)
{
$directoryName = $parentDirectoryName
}
}
if ($remoteFolder)
{
$this.Execute("ADD", @("-commit", $remoteFolder.Name, $directoryName)) | Out-Null
$addedFolders += $directoryName
$directoryName
}
}
}
}
}
}
$client = New-VaultClient $sccHost $sccUser $sccPassword "your repository name here"
switch -regex ($sccAction)
{
"^GET$" {
"Getting out-of-date files from vault..."
$client.GetLatest("$/some/solution/path/Packages")
}
"^ADD$" {
"Adding missing files to vault..."
$client.AddMissingFiles("$/some/solution/path/Packages")
}
default {
throw "Unknown action. Expected GET or ADD."
}
}
"Done"