protected override void GetChildItems(string path, bool recurse) { WriteVerbose(string.Format("XmlNavigationProvider::GetChildItems(Path = '{0}', recurse = '{1}')", path, recurse)); string xpath = XmlProviderUtils.NormalizePath(path); // Don't need to remove the drive from the path since container provider infrastructure does that // for me automatically XmlDriveInfo drive = base.PSDriveInfo as XmlDriveInfo; XmlDocument xml = drive.XmlDocument; XmlNodeList nodes = xml.SelectNodes(xpath, drive.NamespaceManager); // ------------------------------ // NOTE: We could create an ErrorRecord and call WriteError() if SelectNodes() returns null. // In this case I decided not to because the fact that get-item returns // nothing indicates that case. For other operations such as clear-item or set-item // it is a good idea to throw that exception to indicate specifically why you're unable to // perform the action. // ------------------------------ foreach (XmlNode node in nodes) { foreach (XmlNode innerNode in node.ChildNodes) { WriteItemObject(innerNode, path, IsNodeContainer(innerNode)); } } }
protected override bool IsValidPath(string path) { Console.WriteLine("XmlNavigationProvider::IsValidPath(Path = '{0}')", path); WriteVerbose(string.Format("XmlNavigationProvider::IsValidPath(Path = '{0}')", path)); // Check if the path is null or empty. if (string.IsNullOrEmpty(path)) { return(false); } // Convert all separators in the path to a uniform one. path = XmlProviderUtils.NormalizePath(path); // Split path string[] pathChunks = path.Split(XmlProviderUtils.XML_PATH_SEP.ToCharArray()); foreach (string pathChunk in pathChunks) { if (pathChunk.Length == 0) { return(false); } } return(true); }
/// <summary> /// move-item cmdlet callback /// Basically the same as CopyItem except we remove the nodes from their original location after /// they get copied over. /// </summary> /// <param name="path"></param> /// <param name="destination"></param> protected override void MoveItem(string path, string destination) { WriteVerbose(string.Format("XmlNavigationProvider::MoveItem(Path = '{0}', destination = '{1}')", path, destination)); string xpath = XmlProviderUtils.NormalizePath(path); XmlNodeList nodes = GetXmlNodesFromPath(xpath); XmlNode destNode = GetSingleXmlNodeFromPath(destination); XmlDocument xmldoc = GetXmlDocumentFromCurrentDrive(); if (xmldoc == null) { return; } foreach (XmlNode nd in nodes) { if (base.ShouldProcess(nd.Name)) { destNode.AppendChild(nd.Clone()); // remove node from old location nd.ParentNode.RemoveChild(nd); } } }
/// <summary> /// get-item cmdlet callback /// </summary> /// <param name="path"></param> protected override void GetItem(string path) { WriteVerbose(string.Format("XmlItemProvider::GetItem(Path = '{0}')", path)); string npath = XmlProviderUtils.NormalizePath(path); string xpath = XmlProviderUtils.PathNoDrive(npath); XmlDriveInfo drive = XmlProviderUtils.GetDriveFromPath(path, base.ProviderInfo); if (drive == null) { ErrorRecord error = new ErrorRecord(new InvalidProgramException("Unable to retrieve the drive for this path"), "drive", ErrorCategory.InvalidData, null); WriteError(error); } XmlDocument xml = drive.XmlDocument; XmlNodeList nodes = xml.SelectNodes(xpath, drive.NamespaceManager); // ------------------------------ // NOTE: We could throw an ItemNotFoundException here if the nodelist returned is null // or empty. In this case I decided not to because the fact that get-item returns // nothing indicates that case. For other operations such as clear-item or set-item // it is a good idea to throw that exception to indicate specifically why you're unable to // perform the action. // ------------------------------ foreach (XmlNode node in nodes) { WriteItemObject(node, path, false); } }
//clear-item, get-item, invoke-item, set-item // resolve-path, test-path #region ItemCmdletProvider overrides /// <summary> /// clear-item cmdlet callback /// </summary> /// <param name="path"></param> protected override void ClearItem(string path) { WriteVerbose(string.Format("XmlItemProvider::ClearItem(Path = '{0}')", path)); string npath = XmlProviderUtils.NormalizePath(path); string xpath = XmlProviderUtils.PathNoDrive(npath); XmlNodeList nodes = GetXmlNodesFromPath(xpath); // throw terminating error if we can't find any items at path // ------------------------------------------------ if (nodes == null || nodes.Count == 0) { ErrorRecord error = new ErrorRecord(new ItemNotFoundException(), "ItemNotFound", ErrorCategory.ObjectNotFound, null); ThrowTerminatingError(error); } foreach (XmlNode node in nodes) { // ShouldProcess() enables use of -whatif & -confirm flags for clear-item // If path returns more than a single XMLNode, we call ShouldProcess() for each // node not one call to ShouldProcess for the entire operation // ----------------------------------------------------------- if (base.ShouldProcess(node.Name)) { node.RemoveAll(); } } }
/// <summary> /// verifies item specified by path is a container which will allow the usre to navigate to this location as well /// as other container related operations. /// </summary> /// <param name="path"></param> /// <returns></returns> protected override bool IsItemContainer(string path) { WriteVerbose(string.Format("XmlNavigationProvider::IsItemContainer(Path = '{0}')", path)); // see if item exists at path and indicate if it is container // if its a container, we can set-location to it string xpath = XmlProviderUtils.NormalizePath(path); // Note: We assume that user is setting location to the first XMLNode of possibly more than // one. What we might want to do is provide some syntax that indicates which of multiple nodes of same name // to change to. Something like 'drive:\root\node[4]' to indicate the 4th node. This will require more manipulation // of the path to make sure we strip it before it does to the xpath query. // ----------------------------------------------------------------------- XmlNode node = GetSingleXmlNodeFromPath(xpath); if (node == null) { return(false); } else { return(IsNodeContainer(node)); } }
// copy-item, get-childitem, new-item, remove-item, rename-item #region ContainerCmdletProvider overrides /// <summary> /// cmdlet callback for copy-item /// </summary> /// <param name="path"></param> /// <param name="copyPath"></param> /// <param name="recurse"></param> protected override void CopyItem(string path, string copyPath, bool recurse) { WriteVerbose(string.Format("XmlContainerProvider::CopyItem(Path = '{0}', CopyPath = '{1}', recurse = '{2}')", path, copyPath, recurse)); string xpath = XmlProviderUtils.NormalizePath(path); XmlNodeList nodes = GetXmlNodesFromPath(xpath); if (nodes == null || nodes.Count == 0) { ErrorRecord error = new ErrorRecord(new ItemNotFoundException("Source item not found"), "ItemNotFound", ErrorCategory.ObjectNotFound, path); WriteError(error); } // Now that we have the node(s) to copy we need to figure out where to copy them // There are 3 possible scenarios here: // 1) there's already an XML node at the place indicated by copyPath // 2) There's not a node there but the node indicated by the path minus the childitem name exists // i.e. \root\one\two\three , \root\one\two exists but \root\one\two\three doesn't // 3) The path doesn't exist somewhere in the middle, there is no item. // i.e. \root\one\two\three , \root\one exists but not \root\one\two. which means we couldn't copy // to \root\one\two\three without creating the \two\ item inbetween one & three. This is one of // those internal provider details. The typical behavior here is to create any missing inbetween // nodes if the -force flag is specified. XmlNode destNode = GetSingleXmlNodeFromPath(copyPath); if (destNode == null) { ErrorRecord error = new ErrorRecord(new ItemNotFoundException("Destination item not found"), "ItemNotFound", ErrorCategory.ObjectNotFound, copyPath); WriteError(error); } XmlDocument xmldoc = GetXmlDocumentFromCurrentDrive(); if (xmldoc == null) { return; } foreach (XmlNode nd in nodes) { if (base.ShouldProcess(nd.Name)) { destNode.AppendChild(nd.Clone()); } } }
// copy-item, get-childitem, new-item, remove-item, rename-item #region ContainerCmdletProvider overrides protected override void CopyItem(string path, string copyPath, bool recurse) { WriteVerbose(string.Format("XmlNavigationProvider::CopyItem(Path = '{0}', CopyPath = '{1}', recurse = '{2}')", path, copyPath, recurse)); string xpath = XmlProviderUtils.NormalizePath(path); XmlNodeList nodes = GetXmlNodesFromPath(xpath); // Now that we have the node(s) to copy we need to figure out where to copy them // There are 3 possible scenarios here: // 1) there's already an XML node at the place indicated by copyPath // 2) There's not a node there but the node indicated by the path minus the childitem name exists // i.e. \root\one\two\three , \root\one\two exists but \root\one\two\three doesn't // 3) The path doesn't exist somewhere in the middle, there is no item. // i.e. \root\one\two\three , \root\one exists but not \root\one\two. which means we couldn't copy // to \root\one\two\three without creating the \two\ item inbetween one & three. This is one of // those internal provider details. The typical behavior here is to create any missing inbetween // nodes if the -force flag is specified. XmlNode destNode = GetSingleXmlNodeFromPath(copyPath); XmlDocument xmldoc = GetXmlDocumentFromCurrentDrive(); if (xmldoc == null) { return; } foreach (XmlNode nd in nodes) { if (base.ShouldProcess(nd.Name)) { /* * XmlNode newChildNode = xmldoc.ImportNode( * nd, * recurse); * destNode.AppendChild(newChildNode); * * // attributes * destNode.Attributes.RemoveAll(); * foreach (XmlAttribute attrib in nd.Attributes) * { * destNode.Attributes.Append(attrib.Clone()); * } */ destNode.AppendChild(nd.Clone()); } } }
protected override void GetChildNames(string path, ReturnContainers returnContainers) { Console.WriteLine("XmlNavigationProvider::GetChildNames(Path = '{0}')", path); WriteVerbose(string.Format("XmlNavigationProvider::GetChildNames(Path = '{0}', ReturnContainers = '{1}'", path, returnContainers)); string xpath = XmlProviderUtils.NormalizePath(path); XmlNode node = GetSingleXmlNodeFromPath(xpath); foreach (XmlNode nd in node.ChildNodes) { WriteItemObject(nd, path, IsNodeContainer(nd)); } }
public XmlNode GetSingleXmlNodeFromPath(string path) { string npath = XmlProviderUtils.NormalizePath(path); string xpath = XmlProviderUtils.PathNoDrive(npath); XmlDriveInfo drive = base.PSDriveInfo as XmlDriveInfo; if (drive == null) { ErrorRecord error = new ErrorRecord(new InvalidProgramException("Unable to retrieve the drive for this path"), "drive", ErrorCategory.InvalidData, null); ThrowTerminatingError(error); } XmlDocument xml = drive.XmlDocument; return(xml.SelectSingleNode(xpath)); }
protected override void RemoveItem(string path, bool recurse) { WriteVerbose(string.Format("XmlNavigationProvider::RemoveItem(Path = '{0}', recurse = '{1}')", path, recurse)); string xpath = XmlProviderUtils.NormalizePath(path); XmlNodeList nodes = GetXmlNodesFromPath(xpath); // NOTE: since we remove nodes, the -recurse flag is kind of assumed. Once a node is removed any of // its children are removed also so no need to recurse any further. // ------------------------------------------------------------- foreach (XmlNode node in nodes) { if (base.ShouldProcess(node.Name)) { node.ParentNode.RemoveChild(node); } } }
protected override bool HasChildItems(string path) { Console.WriteLine("XmlNavigationProvider::HasChildItems(Path = '{0}')", path); WriteVerbose(string.Format("XmlNavigationProvider::HasChildItems(Path = '{0}')", path)); string xpath = XmlProviderUtils.NormalizePath(path); XmlNode node = GetSingleXmlNodeFromPath(xpath); if (node.HasChildNodes) { return(true); } else { return(false); } }
private XmlNodeList GetXmlNodesFromPath(string path) { string npath = XmlProviderUtils.NormalizePath(path); string xpath = XmlProviderUtils.PathNoDrive(npath); XmlDriveInfo drive = XmlProviderUtils.GetDriveFromPath(path, base.ProviderInfo); if (drive == null) { ErrorRecord error = new ErrorRecord(new InvalidProgramException("Unable to retrieve the drive for this path"), "drive", ErrorCategory.InvalidData, null); WriteError(error); return(null); } XmlDocument xml = drive.XmlDocument; return(xml.SelectNodes(xpath)); }
protected override void RenameItem(string path, string newName) { WriteVerbose(string.Format("XmlNavigationProvider::RenameItem(Path = '{0}', newname = '{1}')", path, newName)); // create new node with new name and then copy childnodes and attributes over // -------------------------------------------------------------------------- string xpath = XmlProviderUtils.NormalizePath(path); XmlNodeList nodes = GetXmlNodesFromPath(xpath); XmlDriveInfo drive = base.PSDriveInfo as XmlDriveInfo; XmlDocument xmldoc = drive.XmlDocument; foreach (XmlNode nd in nodes) { if (ShouldProcess(path)) { XmlNode newNode = xmldoc.CreateNode(nd.NodeType, newName, nd.ParentNode.NamespaceURI); nd.ParentNode.ReplaceChild(newNode, nd); } } }
protected override bool ItemExists(string path) { WriteVerbose(string.Format("XmlNavigationProvider::ItemExists(Path = '{0}')", path)); string xpath = XmlProviderUtils.NormalizePath(path); XmlDriveInfo drive = base.PSDriveInfo as XmlDriveInfo; if (drive == null) { return(false); } XmlDocument xml = drive.XmlDocument; if (xml.SelectSingleNode(xpath, drive.NamespaceManager) == null) { return(false); } else { return(true); } }
/// <summary> /// new-item cmdlet callback /// </summary> /// <param name="path"></param> /// <param name="itemTypeName"></param> /// <param name="newItemValue"></param> protected override void NewItem(string path, string itemTypeName, object newItemValue) { WriteVerbose(string.Format("XmlContainerProvider::RemoveItemNewItem(Path = '{0}', itemtype = '{1}', newvalue = '{2}')", path, itemTypeName, newItemValue)); // first check if item already exists at that path // ----------------------------------------------- string xpath = XmlProviderUtils.NormalizePath(path); // we need to get the parent of the new node so we can add to its children // we do this by chooping the last item from the path // for example: new item path = drive:/root/one/two // the parent node would be at drive:/root/one // -------------------------------------------- XmlNode parent = GetParentNodeFromLeaf(xpath); string endName = GetLeafNameFromPath(xpath); XmlDriveInfo drive = base.PSDriveInfo as XmlDriveInfo; XmlDocument xmldoc = drive.XmlDocument; XmlNode newNode = xmldoc.CreateNode(itemTypeName, endName, parent.NamespaceURI); parent.AppendChild(newNode); }
protected override void GetItem(string path) { WriteVerbose(string.Format("XmlNavigationProvider::GetItem(Path = '{0}')", path)); string xpath = XmlProviderUtils.NormalizePath(path); // Don't need to remove the drive from the path since container provider infrastructure does that // for me automatically XmlDriveInfo drive = base.PSDriveInfo as XmlDriveInfo; XmlDocument xml = drive.XmlDocument; XmlNodeList nodes = xml.SelectNodes(xpath, drive.NamespaceManager); // ------------------------------ // NOTE: We could throw an ItemNotFoundException here if the nodelist returned is null // or empty. In this case I decided not to because the fact that get-item returns // nothing indicates that case. For other operations such as clear-item or set-item // it is a good idea to throw that exception to indicate specifically why you're unable to // perform the action. // ------------------------------ foreach (XmlNode node in nodes) { WriteItemObject(node, path, false); } }
protected override void NewItem(string path, string itemTypeName, object newItemValue) { WriteVerbose(string.Format("XmlNavigationProvider::RemoveItemNewItem(Path = '{0}', itemtype = '{1}', newvalue = '{2}')", path, itemTypeName, newItemValue)); // first check if item already exists at that path // ----------------------------------------------- string xpath = XmlProviderUtils.NormalizePath(path); // we need to get the parent of the new node so we can add to its children // we do this by chopping the last item from the path if there isn't already an item // at the path. in which case we need to check force flag or error out // for example: new item path = drive:/root/one/two // the parent node would be at drive:/root/one // -------------------------------------------- XmlNode parent = null; XmlNode destNode = GetSingleXmlNodeFromPath(xpath); if (destNode != null) { parent = destNode.ParentNode; if (base.Force) { destNode.ParentNode.RemoveChild(destNode); } else { // write error ErrorRecord err = new ErrorRecord(new ArgumentException("item already exists!"), "AlreadyExists", ErrorCategory.InvalidArgument, path); WriteError(err); return; } } else { parent = GetParentNodeFromLeaf(xpath); } if (parent == null) { // write error ErrorRecord err = new ErrorRecord(new ItemNotFoundException("ParentPath doesn't exist"), "ObjectNotFound", ErrorCategory.ObjectNotFound, path); WriteError(err); return; } string endName = GetLastPathName(xpath); XmlDriveInfo drive = base.PSDriveInfo as XmlDriveInfo; XmlDocument xmldoc = drive.XmlDocument; XmlNode newNode = xmldoc.CreateNode(itemTypeName, endName, parent.NamespaceURI); // lets call shouldprocess if (ShouldProcess(path)) { parent.AppendChild(newNode); } }