Pulling a single label is simple. Pulling multiple means that per-label directories need to be created and used for each invocation of TF GET.
The steps required to pull a label from TFS as part of an automated build are as follows:
1) Specify the following as input parameters:
Disk location where label is pulled (source code directory)
TFS work space and folder from which code is pulled
Label name associated with TS work space and folder
2) Delete existing code from the source code directory
3) Create the source code directory
4) Change the current-working directory to the source code directory
The reason for this is outlined in: "Build Automation: Getting multiple labels from TFS using TF GET (without deleting the files associated with the previous TF GET)"
5) Delete the TFS work space if it exists
a.k.a. tf workspace /delete
6) Create the TFS work space
a.k.a. tf workspace /new
a.k.a. tf workfold /map
a.k.a. tf get /version
1) Input Parameters and Setup
The input parameters will be as follows corresponding to the location on disk, the collection\folder within TFS and the label associated with the aforementioned collection\folder:
$TFSDiskLocation = 'C:\MarkI\Inventory App';
$Collection = 'MarkI\Inventory App';
$Label = 'InventoryApp1.2.3.4';
GetCode $TFSDiskLocation $Collection $Label;
The three parameters are passed to the GetCode method which is as follows:
function GetCode
{
[CmdletBinding()]
param
(
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string] $TFSDiskLocation,
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string] $Collection,
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string] $Label
)
process
{
$Workspace = $Collection;
$Workspace = CleanWorkspaceName $Workspace;
TFSGetLabel $TFSDiskLocation $Workspace $Collection $Label;
}
}
The previous code simply creates a TFS work space name based on the collection containing the code. The work space name is then passed to the TFSGetLabel function that actually performs all the steps required to get the code.
The function CleanWorkspaceName converts a collection into a legal work space name since it creates a work space name based on the restrictions TFS. The function CleanWorkspaceName uses a global parameter that insures the work space name does not exceed TFS' work space name length limitation as specified in "Naming Restrictions in Team Foundation":
$gTFSWorkspaceNameLength = 64;
The character restrictions are also presented in "Naming Restrictions in Team Foundation" which (to quote) are as follows:
- Must not include the following printable characters: "/ \ [ ] : | < > + = ; ? *
- Must not include nonprintable characters in the ASCII value range of 1-31
- Must not end in a period (.)
- Must not include commas (,)
The function CleanWorkspaceName is as follow where the code simply adheres to the previously discussed name length and character restrictions:
function CleanWorkspaceName
{
[CmdletBinding()]
param
(
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string] $WorkspaceName
)
process
{
# Append computer name to workspace to aid debugging.
# Remove trailing and leading spaces with Trim.
$WorkspaceName = $env:computername + $WorkspaceName.Trim();
# invalid workspace name characters: /:<>\|*?;
$WorkspaceName = $WorkspaceName.Replace('/', '');
$WorkspaceName = $WorkspaceName.Replace(':', '');
$WorkspaceName = $WorkspaceName.Replace('<', '');
$WorkspaceName = $WorkspaceName.Replace('>', '');
$WorkspaceName = $WorkspaceName.Replace('\', '');
$WorkspaceName = $WorkspaceName.Replace('|', '');
$WorkspaceName = $WorkspaceName.Replace('*', '');
$WorkspaceName = $WorkspaceName.Replace('?', '');
$WorkspaceName = $WorkspaceName.Replace(';', '');
$WorkspaceName = $WorkspaceName.Replace(',', '');
$WorkspaceName = $WorkspaceName.Replace('.', '');
# change spaces to underscore to avoid naming issues
$WorkspaceName = $WorkspaceName.Replace(' ', '_');
if ($WorkspaceName.Length -gt $gTFSWorkspaceNameLength)
{
$WorkspaceName = $WorkspaceName.Substring(0,
$gTFSWorkspaceNameLength);
}
return $WorkspaceName;
}
}
2) Delete existing code from source code directory
In order to clean up the build location from a previous build, the source code location is deleted. This step is handled by the DeleteDirectory function which behaves as follows:
1) List all files in directory
1.1) If the file is read-only, clear the read-only flag
1.2) Delete the file
2) List all sub-directories
2.1) Invoke the DeleteDirectory on the sub-directory
2.2) Delete the sub-directory
function DeleteDirectory
{
[CmdletBinding()]
param
(
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String] $directory
)
process
{
if (![System.IO.Directory]::Exists($directory))
{
return ;
}
$files = @();
$files += [System.IO.Directory]::GetFiles($directory);
foreach ($file in $files)
{
$attributes = [System.IO.File]::GetAttributes($file);
if ($attributes -band
[System.IO.FileAttributes]::ReadOnly)
{
$attributes = [int]$attributes -
[int][System.IO.FileAttributes]::ReadOnly;
[System.IO.File]::SetAttributes($file,
$attributes);
$attributes);
}
# Write-Host "[System.IO.File]::Delete($file)";
[System.IO.File]::Delete($file);
}
$directories = @();
$directories += [System.IO.Directory]::GetDirectories(
$directory);
foreach ($subDirectory in $directories)
{
DeleteDirectory $subDirectory;
}
# Write-Host "[System.IO.Directory]::Delete($directory)";
[System.IO.Directory]::Delete($directory);
}
}
The previous code is self-explanatory (basic file I/O).
The DeleteDirectory function is invoked from TFSGetLabel as follows which is the first action taken as part of the source code retrieval process:
function TFSGetLabel
{
[CmdletBinding()]
param
(
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String] $SourceFolder,
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String] $WorkSpace,
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String] $Collection,
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String] $Label
)
process
{
try
{
Write-Host 'TFSGetLabel:SourceFolder $SourceFolder';
Write-Host 'TFSGetLabel:Label $Label';
DeleteDirectory $SourceFolder;
$DirectoryInfo = [System.IO.Directory]::CreateDirectory(
$SourceFolder);
[System.IO.Directory]::SetCurrentDirectory(
$SourceFolder);
$cwd = [System.IO.Directory]::GetCurrentDirectory();
Write-Host "CWD: $cwd";
The invocation of DeleteDirectory is accented in boldface above.
3) Create the source code directory
The creation of the source code directory in TFSGetLabel as follows where the action is indicated by the line in boldface:
Write-Host 'TFSGetLabel:SourceFolder $SourceFolder';
Write-Host 'TFSGetLabel:Label $Label';
DeleteDirectory $SourceFolder;
$DirectoryInfo = [System.IO.Directory]::CreateDirectory(
$SourceFolder);
[System.IO.Directory]::SetCurrentDirectory(
$SourceFolder);
$cwd = [System.IO.Directory]::GetCurrentDirectory();
Write-Host "CWD: $cwd";
Write-Host 'TFSGetLabel:Label $Label';
DeleteDirectory $SourceFolder;
$DirectoryInfo = [System.IO.Directory]::CreateDirectory(
$SourceFolder);
[System.IO.Directory]::SetCurrentDirectory(
$SourceFolder);
$cwd = [System.IO.Directory]::GetCurrentDirectory();
Write-Host "CWD: $cwd";
4) Change the current-working directory to the source code directory
Changing the current working directory to be the same as the source code directory in TFSGetLabel as follows where the action is indicated by the line in boldface:
Write-Host 'TFSGetLabel:SourceFolder $SourceFolder';
Write-Host 'TFSGetLabel:Label $Label';
DeleteDirectory $SourceFolder;
$DirectoryInfo = [System.IO.Directory]::CreateDirectory(
$SourceFolder);
[System.IO.Directory]::SetCurrentDirectory(
$SourceFolder);
$cwd = [System.IO.Directory]::GetCurrentDirectory();
Write-Host "CWD: $cwd";
Write-Host 'TFSGetLabel:Label $Label';
DeleteDirectory $SourceFolder;
$DirectoryInfo = [System.IO.Directory]::CreateDirectory(
$SourceFolder);
[System.IO.Directory]::SetCurrentDirectory(
$SourceFolder);
$cwd = [System.IO.Directory]::GetCurrentDirectory();
Write-Host "CWD: $cwd";
5) Delete the TFS work space if it exists
The code to delete the existing TFS work space relies on the function DoesTFSWorkspaceExist to determine if the work space already exists. The work space is only deleted if it already exists.The DoesTFSWorkspaceExist function using the following global parameter corresponding to TFS's TF function:
$gTFUtility = 'tf';
The DoesTFSWorkspaceExist function:
1) Invokes the tf workspaces using .NET's System.Diagnostics.Process class as invoked via PowerShell.
1.1) The tf workspaces command lists all existing work spaces.
2) Read the output from the tf workspaces command to determine if the work space already exists.
2.1) The output is accessed via the System.Diagnostics.Process class' StandardOutput property.
{
[CmdletBinding()]
param
(
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String] $Workspace
)
process
{
Write-Host
"DoesTFSWorkspaceExist -- workspace: $Workspace";
$ProcessStartInfo = New-Object
System.Diagnostics.ProcessStartInfo;
$ProcessStartInfo.FileName = $gtfUtility;
$ProcessStartInfo.RedirectStandardError = $True;
$ProcessStartInfo.RedirectStandardOutput = $True;
$ProcessStartInfo.UseShellExecute = $False;
# we are invoking: tf workspaces
$ProcessStartInfo.Arguments = "workspaces";
$process = New-Object System.Diagnostics.Process;
$process.StartInfo = $ProcessStartInfo;
# ignore return value with Out-Null
$process.Start() | Out-Null;
$process.WaitForExit();
$ExitCode = $process.ExitCode;
if ($ExitCode -ne 0)
{
$ErrorText = $process.StandardError.ReadToEnd();
Write-Host "Error: $ErrorText.";
throw $ErrorText;
}
$stdout = $process.StandardOutput;
while ($True)
{
$line = $stdout.ReadLine();
# check for null
if (!$line)
{
break;
}
if ($line.ToUpper().StartsWith($Workspace.ToUpper()))
{
Write-Host "Workspace exists: $Workspace";
return $True;
}
}
return $False;
}
}
The DoesTFSWorkspaceExist function is invoked by TFSGetLabel as follows where the action is indicated by the line in boldface:
Write-Host 'TFSGetLabel:SourceFolder $SourceFolder';
Write-Host 'TFSGetLabel:Label $Label';
DeleteDirectory $SourceFolder;
$DirectoryInfo = [System.IO.Directory]::CreateDirectory(
$SourceFolder);
[System.IO.Directory]::SetCurrentDirectory($SourceFolder);
$cwd = [System.IO.Directory]::GetCurrentDirectory();
Write-Host "CWD: $cwd";
# protect against space in name
$SourceFolder = '"' + $SourceFolder + '"';
# protect against space in name
$Collection = '"' + $Collection + '"';
$Label = '"' + $Label + '"';
if (DoesTFSWorkspaceExist($WorkSpace))
{
# e.g. tf workspace /delete WorkSpaceATest /noprompt
$commandLine = 'workspace /delete ' + $WorkSpace +
' /noprompt';
InvokeTF $commandLine $SourceFolder;
}
Write-Host 'TFSGetLabel:Label $Label';
DeleteDirectory $SourceFolder;
$DirectoryInfo = [System.IO.Directory]::CreateDirectory(
$SourceFolder);
[System.IO.Directory]::SetCurrentDirectory($SourceFolder);
$cwd = [System.IO.Directory]::GetCurrentDirectory();
Write-Host "CWD: $cwd";
# protect against space in name
$SourceFolder = '"' + $SourceFolder + '"';
# protect against space in name
$Collection = '"' + $Collection + '"';
$Label = '"' + $Label + '"';
if (DoesTFSWorkspaceExist($WorkSpace))
{
# e.g. tf workspace /delete WorkSpaceATest /noprompt
$commandLine = 'workspace /delete ' + $WorkSpace +
' /noprompt';
InvokeTF $commandLine $SourceFolder;
}
function InvokeTF
{
[CmdletBinding()]
param
(
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String] $CommandLine,
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String] $WorkingDirectory
)
process
{
Write-Host "Working Directory: $WorkingDirectory";
Write-Host "Invoking: $gtfUtility $commandLine";
$ProcessStartInfo = New-Object
System.Diagnostics.ProcessStartInfo;
$ProcessStartInfo.FileName = $gtfUtility;
$ProcessStartInfo.RedirectStandardError = $True;
$ProcessStartInfo.RedirectStandardOutput = $False;
$ProcessStartInfo.UseShellExecute = $False;
$ProcessStartInfo.Arguments = $CommandLine;
$process = New-Object System.Diagnostics.Process;
$process.StartInfo = $ProcessStartInfo;
# ignore return value with Out-Null
$process.Start() | Out-Null;
$process.WaitForExit();
$ExitCode = $process.ExitCode;
if ($ExitCode -ne 0)
{
$ErrorText = $process.StandardError.ReadToEnd();
Write-Host "Error: $ErrorText.";
throw $ErrorText;
}
}
}
The InvokeTF function calls the TF utility using the command-line supplied by the aptly named $CommandLine parameter. The TF utility is run in the same working directory as the source code folder. The source code folder is passed in as the parameter $WorkingDirectory.
The code that called InvokeTF passed as a parameter with the command-line required to delete a work space (workspace /delete <workspacename> /noprompt) which is demonstrated below:
if (DoesTFSWorkspaceExist($WorkSpace))
{
# e.g. tf workspace /delete WorkSpaceATest /noprompt
$commandLine = 'workspace /delete ' + $WorkSpace +
' /noprompt';
InvokeTF $commandLine $SourceFolder;
}
{
# e.g. tf workspace /delete WorkSpaceATest /noprompt
$commandLine = 'workspace /delete ' + $WorkSpace +
' /noprompt';
InvokeTF $commandLine $SourceFolder;
}
6) Create the TFS work space
The TFSGetLabel function contains the code to handle the work space delete, work space creation, folder to work space mapping and getting the label. The work space creation is highlighted below in boldface:# e.g. tf workspace /new WorkSpaceATest /noprompt
$commandLine = 'workspace /new ' + $WorkSpace + ' /noprompt';
InvokeTF $commandLine $SourceFolder;
# e.g. tf workfold /map $/ATest D:\ATest /WorkSpace:WorkSpaceATest
$commandLine = 'workfold /map $/' + $Collection + ' ' + $SourceFolder + ' /WorkSpace:' + $WorkSpace;
InvokeTF $commandLine $SourceFolder;
# e.g. tf get /version:LBTest01
# note the L in /Version:L means a label is specified
$commandLine = 'get /Version:L' + $Label + ' /noprompt';
InvokeTF $commandLine $SourceFolder;
7) Map the source code folder to the collection folder and associate this mapping with the work space
The TFSGetLabel function handling the folder to work space mapping is highlighted below in boldface:# e.g. tf workspace /new WorkSpaceATest /noprompt
$commandLine = 'workspace /new ' + $WorkSpace + ' /noprompt';
InvokeTF $commandLine $SourceFolder;
# e.g. tf workfold /map $/ATest D:\ATest /WorkSpace:WorkSpaceATest
$commandLine = 'workfold /map $/' + $Collection + ' ' + $SourceFolder + ' /WorkSpace:' + $WorkSpace;
InvokeTF $commandLine $SourceFolder;
# e.g. tf get /version:LBTest01
# note the L in /Version:L means a label is specified
$commandLine = 'get /Version:L' + $Label + ' /noprompt';
InvokeTF $commandLine $SourceFolder;
tf workfold /map <collection> <folder> /Workspace:<workspacename>
8) Get label from TFS
The TFSGetLabel function handling retrieving the label is highlighted below in boldface:# e.g. tf workspace /new WorkSpaceATest /noprompt
$commandLine = 'workspace /new ' + $WorkSpace + ' /noprompt';
InvokeTF $commandLine $SourceFolder;
# e.g. tf workfold /map $/ATest D:\ATest /WorkSpace:WorkSpaceATest
$commandLine = 'workfold /map $/' + $Collection + ' ' + $SourceFolder + ' /WorkSpace:' + $WorkSpace;
InvokeTF $commandLine $SourceFolder;
# e.g. tf get /version:LBTest01
# note the L in /Version:L means a label is specified
$commandLine = 'get /Version:L' + $Label + ' /noprompt';
InvokeTF $commandLine $SourceFolder;
tf get /map /Version:L<label name> /noprompt
The capital L after the /Version: option is crucial so that the label is interpreted as a label name and not a version number.
Entire Script
The script in its entirety is as follows:
$gTFUtility = 'tf';
$gTFSWorkspaceNameLength = 64;
function DeleteDirectory
{
[CmdletBinding()]
param
(
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String] $directory
)
process
{
if (![System.IO.Directory]::Exists($directory))
{
return ;
}
$files = @();
$files += [System.IO.Directory]::GetFiles($directory);
foreach ($file in $files)
{
$attributes = [System.IO.File]::GetAttributes($file);
if ($attributes -band
[System.IO.FileAttributes]::ReadOnly)
{
$attributes = [int]$attributes -
[int][System.IO.FileAttributes]::ReadOnly;
[System.IO.File]::SetAttributes($file,
$attributes);
$attributes);
}
# Write-Host "[System.IO.File]::Delete($file)";
[System.IO.File]::Delete($file);
}
$directories = @();
$directories +=
[System.IO.Directory]::GetDirectories($directory);
foreach ($subDirectory in $directories)
{
DeleteDirectory $subDirectory;
}
# Write-Host "[System.IO.Directory]::Delete($directory)";
[System.IO.Directory]::Delete($directory);
}
}
function DoesTFSWorkspaceExist
{
[CmdletBinding()]
param
(
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String] $Workspace
)
process
{
Write-Host
"DoesTFSWorkspaceExist -- workspace: $Workspace";
"DoesTFSWorkspaceExist -- workspace: $Workspace";
$ProcessStartInfo = New-Object
System.Diagnostics.ProcessStartInfo;
$ProcessStartInfo.FileName = $gtfUtility;
$ProcessStartInfo.RedirectStandardError = $True;
$ProcessStartInfo.RedirectStandardOutput = $True;
$ProcessStartInfo.UseShellExecute = $False;
# we are invoking: tf workspaces
$ProcessStartInfo.Arguments = "workspaces";
$process = New-Object System.Diagnostics.Process;
$process.StartInfo = $ProcessStartInfo;
# ignore return value with Out-Null
$process.Start() | Out-Null;
$process.WaitForExit();
$ExitCode = $process.ExitCode;
if ($ExitCode -ne 0)
{
$ErrorText = $process.StandardError.ReadToEnd();
Write-Host "Error: $ErrorText.";
throw $ErrorText;
}
$stdout = $process.StandardOutput;
while ($True)
{
$line = $stdout.ReadLine();
# check for null
if (!$line)
{
break;
}
if ($line.ToUpper().StartsWith($Workspace.ToUpper()))
{
Write-Host "Workspace exists: $Workspace";
return $True;
}
}
return $False;
}
}
function InvokeTF
{
[CmdletBinding()]
param
(
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String] $CommandLine,
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String] $WorkingDirectory
)
process
{
Write-Host "Working Directory: $WorkingDirectory";
Write-Host "Invoking: $gtfUtility $commandLine";
$ProcessStartInfo = New-Object
System.Diagnostics.ProcessStartInfo;
$ProcessStartInfo.FileName = $gtfUtility;
$ProcessStartInfo.RedirectStandardError = $True;
$ProcessStartInfo.RedirectStandardOutput = $False;
$ProcessStartInfo.UseShellExecute = $False;
$ProcessStartInfo.Arguments = $CommandLine;
$process = New-Object System.Diagnostics.Process;
$process.StartInfo = $ProcessStartInfo;
# ignore return value with Out-Null
$process.Start() | Out-Null;
$process.WaitForExit();
$ExitCode = $process.ExitCode;
if ($ExitCode -ne 0)
{
$ErrorText = $process.StandardError.ReadToEnd();
Write-Host "Error: $ErrorText.";
throw $ErrorText;
}
}
}
function TFSGetLabel
{
[CmdletBinding()]
param
(
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String] $SourceFolder,
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String] $WorkSpace,
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String] $Collection,
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[String] $Label
)
process
{
try
{
Write-Host 'TFSGetLabel:SourceFolder $SourceFolder';
Write-Host 'TFSGetLabel:Label $Label';
DeleteDirectory $SourceFolder;
$DirectoryInfo =
[System.IO.Directory]::CreateDirectory(
[System.IO.Directory]::CreateDirectory(
$SourceFolder);
[System.IO.Directory]::SetCurrentDirectory(
$SourceFolder);
$cwd = [System.IO.Directory]::GetCurrentDirectory();
Write-Host "CWD: $cwd";
# protect against space in name
$SourceFolder = '"' + $SourceFolder + '"';
# protect against space in name
$Collection = '"' + $Collection + '"';
$Label = '"' + $Label + '"';
if (DoesTFSWorkspaceExist($WorkSpace))
{
# e.g. tf workspace /delete WorkSpaceATest /noprompt
$commandLine = 'workspace /delete ' +
$WorkSpace + ' /noprompt';
$WorkSpace + ' /noprompt';
InvokeTF $commandLine $SourceFolder;
}
# e.g. tf workspace /new WorkSpaceATest /noprompt
$commandLine = 'workspace /new ' + $WorkSpace +
' /noprompt';
InvokeTF $commandLine $SourceFolder;
# e.g. tf workfold /map $/ATest D:\ATest
# /WorkSpace:WorkSpaceATest
$commandLine = 'workfold /map $/' + $Collection +
' ' + $SourceFolder + ' /WorkSpace:' + $WorkSpace;
' ' + $SourceFolder + ' /WorkSpace:' + $WorkSpace;
InvokeTF $commandLine $SourceFolder;
# e.g. tf get /version:LBTest01
# note the L in /Version:L means a label is specified
$commandLine = 'get /Version:L' + $Label +
' /noprompt';
' /noprompt';
InvokeTF $commandLine $SourceFolder;
}
catch
{
Write-Error "Build Error $SolutionFilePath, $_";
Write-Error "Build Error $SolutionFilePath, $_";
Exit 1;
}
}
}
function CleanWorkspaceName
{
[CmdletBinding()]
param
(
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string] $WorkspaceName
)
process
{
# Add computer name to work space to aid in debugging.
# Remove trailing and leading spaces with Trim
$WorkspaceName = $env:computername +
$WorkspaceName.Trim();
$WorkspaceName.Trim();
# invalid workspace name characters: /:<>\|*?;
$WorkspaceName = $WorkspaceName.Replace('/', '');
$WorkspaceName = $WorkspaceName.Replace(':', '');
$WorkspaceName = $WorkspaceName.Replace('<', '');
$WorkspaceName = $WorkspaceName.Replace('>', '');
$WorkspaceName = $WorkspaceName.Replace('\', '');
$WorkspaceName = $WorkspaceName.Replace('|', '');
$WorkspaceName = $WorkspaceName.Replace('*', '');
$WorkspaceName = $WorkspaceName.Replace('?', '');
$WorkspaceName = $WorkspaceName.Replace(';', '');
$WorkspaceName = $WorkspaceName.Replace('.', '');
$WorkspaceName = $WorkspaceName.Replace(',', '');
# change spaces to underscore
# change spaces to underscore
$WorkspaceName = $WorkspaceName.Replace(' ', '_');
if ($WorkspaceName.Length -gt $gTFSWorkspaceNameLength)
{
$WorkspaceName = $WorkspaceName.Substring(0,
$gTFSWorkspaceNameLength);
}
return $WorkspaceName;
}
}
function GetCode
{
[CmdletBinding()]
param
(
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string] $TFSDiskLocation,
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string] $Collection,
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string] $Label
)
process
{
$Workspace = $Collection;
$Workspace = CleanWorkspaceName $Workspace;
TFSGetLabel $TFSDiskLocation $Workspace
$Collection $Label;
$Collection $Label;
}
}
$TFSDiskLocation = 'C:\MarkI\Inventory App';
$Collection = 'MarkI\Inventory App';
$Label = 'InventoryApp1.2.3.4';
GetCode $TFSDiskLocation $Collection $Label;
Fantastic write up.
ReplyDeleteGreat code examples. Just what I was looking for. But eg the Delete directory why are you not using more powershell cmd. I think you could do something like: get-childitem $directory -include * -recurse | Remove-Item -recurse –force that would be less code imho you are using tf.exe could it work the PSSnapin Microsoft.TeamFoundation.PowerShell ?
ReplyDeleteThanks for the feedback.
DeleteIn a few of my posts I mention that my team and I are C# developers which is why I favor file I/O .NET System.IO. On projects where my team maintains with me (build task) I code more like C#. For other tasks, I code pure PowerShell.
The same bias is why I use TF over PSSnapin. Every developer on the team has TF installed with Visual Studio.