As per requirement, search file in specific child folder and then copy to destination path. I had implemented in c#.NET earlier but now want to convert in PowerShell.
foreach (var directory in Directory.EnumerateDirectories(sourcePath, specificChildFolder, SearchOption.AllDirectories))
{
var pathSrc = Path.Combine(directory, "xyz.config");
if (File.Exists(pathSrc))
{
File.Copy(pathSrc, pathDst, true);
break;
}
}
Here is code which you can use:
$path = "C:\Users\user1\Desktop\Config Rework\"
$destination = "c:\destination\"
foreach ($filepath in [System.IO.Directory]::EnumerateFiles($path,"xyz.config","AllDirectories"))
{
$file = New-Object System.IO.FileInfo($filepath)
if(Test-Path $file)
{
write-host $file.FullName
copy $file $destination
Write-Host 'Copied' $file ' to ' $destination
}
}
Output:
C:\Users\user1\Desktop\Config Rework\xyz\xyz.config
Copied C:\Users\user1\Desktop\Config Rework\xyz\xyz.config to c:\destination\
This has looped through the child folders under C:\Users\user1\Desktop\Config Rework, checked if xyz.config exists and then copied it to the destination folder.
Note that if your directory looks as follows:
xyz.config under xyz folder will take precedence as it will loop through the child folder.
Related
One of utility we created generates too many files in C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys. To safely delete these files I want to open each file and exam the key. How can I open these key files in C#? I looked at code at here. The code only returns public key. Can I get more information form these key files?
I ended up using following powershell to get a list of valid key from certificate store. I also added c2319c42033a5ca7f44e731bfd3fa2b5 to the list since I am using IIS service. I delete any key file not in this list.
$MachineCertStores = Get-ChildItem Cert:\LocalMachine
$UserCertStores = Get-ChildItem Cert:\CurrentUser
Foreach ($Store in $MachineCertStores)
{
$path = "Cert:\LocalMachine\" + $($store.Name)
$keys = Get-ChildItem $path
Foreach ($Key in $Keys)
{
$UniqueKeyName = $key.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName
if ([string]::IsNullOrWhitespace($UniqueKeyName)){
}else{
write-host $UniqueKeyName
$file = Get-Content "validkey.txt"
$containsWord = $file | %{$_ -match $UniqueKeyName.substring(0,32)}
If($containsWord -contains $true)
{
}else{
$UniqueKeyName.substring(0,32) | Out-File 'validkey.txt' -Append
}
}
}
}
Foreach ($Store in $UserCertStores)
{
$path = "Cert:\CurrentUser\" + $($store.Name)
$keys = Get-ChildItem $path
Foreach ($Key in $Keys)
{
$UniqueKeyName = $key.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName
if ([string]::IsNullOrWhitespace($UniqueKeyName)){
}else{
write-host $UniqueKeyName
$file = Get-Content "validkey.txt"
$containsWord = $file | %{$_ -match $UniqueKeyName.substring(0,32)}
If($containsWord -contains $true)
{
}else{
$UniqueKeyName.substring(0,32) | Out-File 'validkey.txt' -Append
}
}
}
}
Task: I need to loop thru all files on Sharepoint site and download them to local folder.
Script:
Add-PSSnapin Microsoft.SharePoint.PowerShell -ErrorAction SilentlyContinue
$s = Get-SPSite “https://abc.abctools.consumer.abc.net/sites/rtc/report/SitePages/Forms/AllPages.aspx”
$files = $s.RootWeb.GetFolder("Shared Documents").Files
foreach ($file in $files) {
Write-host $file.Name
$b = $file.OpenBinary()
$fs = New-Object System.IO.FileStream(("C:\SP Document Library files\"+$file.Name), [System.IO.FileMode]::Create)
$bw = New-Object System.IO.BinaryWriter($fs)
$bw.Write($b)
$bw.Close()
}
Errors: I get when i try to run/execute above script.
1. "You cannot call a method on a null-valued expression."
New-Object: Exception calling ".ctor" with "2" agrument(s): "Could not find a part of the path 'C:\SP Document Library files\'
New-Object: Constructor not found. Cannot find an appropriate constructor for the type system.IO.BinaryWrite.
The term 'Get-SPSite' is not recognized as a cmdlet, function, operable program or script file. verify the term and try again.
Response on Error #2: I have created the folder & named "SP Document Library files" so that path is correct C:\SP Document Library files not sure why i see that msg.
Library files (.csv,.xls) exists in a folder.
Folder name : 2014-01-31.
1. What to do to in order resolve above error message(s).
2. I'm not sure if i need to use whole sharepoint url or part of it.Educate me on that.
Thanks!!
Try by giving ReadWrite FileAccess.
And you can get the root web directly if you know the Url instead of using SPSite.
Here's my script I use and has always worked
$siteUrl = '“https://abc.abctools.consumer.abc.net/sites/rtc”'
$listUrl = '“https://abc.abctools.consumer.abc.net/sites/rtc/Shared Documents”'
$folderPath = 'C:\\....'
$web = Get-SPWeb -Identity $siteUrl
$list = $web.GetList($listUrl)
$items = $list.Items
ForEach ($item in $items)
{
$binary = $item.File.OpenBinary();
$folderPathToSave = $folderPath + "\\" + $item.Name;
if ($binary -ne $null)
{
$stream = New-Object System.IO.FileStream($folderPathToSave,[System.IO.FileMode]::Create,[System.IO.FileAccess]::ReadWrite);
$writer = New-Object System.IO.BinaryWriter($stream);
$writer.Write($binary);
$writer.Close();
}
}
$web.Dispose()
The original post:
http://naimmurati.wordpress.com/2012/06/07/backup-documents-from-document-library-with-powershell-script/
I am having an issue with trying to make a list by searching through a file structure. Was trying to make a basic c# console program that would just run and do this.
My structure is organize like the following.
My Network \
X1 \
Users \
(many many user folders) \
Search for a specific sub folder \
make a list in a text file of any folders within this sub folder
So i have to be able to search every user folder and then check for a folder (this will be the same every time) Then make a list of the found folders within that sub folder with the following format
username (name of the user folder) >> Name of folder within the specific folder.
its been a terribly long time since i have had to try anything with searching within a file structure so blanking on this terribly.
**************** EDIT!!!!!
Thanks for the info and links. Working on this now but wondering if this makes sense and would work. Don't want to just test it before i make sure it looks like something that wouldn't just screw up.
TextWriter outputText = new StreamWriter(#"C:\FileList.txt", true);
outputText.WriteLine("Starting scan through user folder");
string path = #"\\X1\users";
string subFolder = "^^ DO NOT USE - MY DOCS - BACKUP ^^";
string [] user_folders = Directory.GetDirectories(path);
foreach (var folder in user_folders)
{
string checkDirectory = folder + "\\" + subFolder;
if (Directory.Exists(checkDirectory) == true)
{
string [] inner_folders = Directory.GetDirectories(checkDirectory);
foreach (var folder2 in inner_folders)
{
outputText.WriteLine(folder2);
}
}
}
outputText.WriteLine("Finishing scan through user folder");
outputText.Close();
Fixed and working!!!! had to change the string [] lines, to make it .GetDirectories instead of .GetFiles!!
As Bali C mentioned, the Directory class will be your friend on this one. The following examples should get you started.
From: http://social.msdn.microsoft.com/Forums/en-US/Vsexpressvcs/thread/3ea19b83-b831-4f30-9377-bc1588b94d23/
//Obviously you'll need to define the correct path.
string path = #"My Network\X1\Users\(many many user folders)\Search for a specific sub folder \";
// Will Retrieve count of all files in directry and sub directries
int fileCount = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories).Length;
// Will Retrieve count of all files in directry but not sub directries
int fileCount = Directory.GetFiles(path, "*.*", SearchOption.TopDirectory).Length;
// Will Retrieve count of files .txt extensions in directry and sub directries
int fileCount = Directory.GetFiles(path, "*.txt", SearchOption.AllDirectories).Length;
If you need to search the /Users/ folder for certain people, or certain conditions you could do the following:
string path = #"PATH_TO_USERS_DIRECTORY";
string [] user_folders = Directory.GetFiles(path);
foreach(var folder in user_folders)
{
if folder == "MyFolder";
Process(folder); //Search the directory here.
}
Try the following implementation. This will just write to the console:
const string root = "<<your root path>>";
const string directoryToLookFor = "<<the folder name you are looking for>>";
foreach (var directory in Directory.EnumerateDirectories(root, "*.*", SearchOption.TopDirectoryOnly))
{
var foundDirectory = Directory.EnumerateDirectories(directory, directoryToLookFor, SearchOption.TopDirectoryOnly).FirstOrDefault();
if (!String.IsNullOrEmpty(foundDirectory))
{
var filesInside = Directory.GetFiles(foundDirectory);
foreach (var file in filesInside)
{
Console.WriteLine(file);
}
}
}
Or you could just do:
foreach (var foundDirectory in Directory.EnumerateDirectories(root, directoryToLookFor, SearchOption.AllDirectories))
{
var filesInside = Directory.GetFiles(foundDirectory);
foreach (var file in filesInside)
{
Console.WriteLine(file);
}
}
Which would search within all subdirectories without you having to iterate over the users' folders.
I want to be able to replicate only the folder structure (not the contents) from one location to another in c# 3.5
for example
C:\Some Folder
+ Folder A
+ Sub Folder A
+ Sub Folder B
+ Sub Folder B1
+ Sub Folder B2
+ Sub Folder C
To New Location
C:\Some New folder
+ Folder A
+ Sub Folder Aetc... etc..
Do you mean you want to create the same files, but not the contents within the same structure.
Something like this might work:
public static TotallyNotRecursiveAndCreateDirs(string root, string newRoot)
{
DirectoryInfo rootDir = new DirectoryInfo(Path.GetPathRoot(root));
DirectoryInfo[] dirs = rootDir.GetDirectories("*", SearchOption.AllDirectories);
foreach(DirectoryInfo dir in dirs)
{
Directory.CreateDirectory(dir.FullName.Replace(root, newRoot));
FileInfo[] files = dir.GetFiles("*.*", SearchOption.TopDirectoryOnly);
foreach(FileInfo file in files)
{
File.Create(file.FullName.Replace(root, newRoot));
}
}
}
You might also want to do some exception checking to ensure that the root and the newRoot parameters are valid (ie: rooted, etc...)
If you don't want the files and just the directories, then just remove the second loop.
To copy a folder structure at src to dest:
Create dest.
(Optional) Set permissions on dest to match src.
For each folder name in src, copy the folder structure at src\name to dest\name.
I have searched the SO but find nothing.
Why this doesn't work?
Directory.Delete(#"E:\3\{90120000-001A-0000-0000-0000000FF1CE}-C");
Above line will throw exception "Access is denied". I have admin rigths and I can delete the dir with Explorer.
It looks like some forbidden chars? but Windows Explorer can handle it. How can I delete directories with names like that?
Thank you all for your input, it helps me in quick find of solution.
As Phil mentioned "Directory.Delete fails if it is, regardless of permissions (see bottom of msdn.microsoft.com/en-us/library/…)"
In addition Unable to remove Read-Only attribute from folder
Microsoft says:
You may be unable to remove the
Read-Only attribute from a folder
using Windows Explorer. In addition,
some programs may display error
messages when you try to save files to
the folder.
Conclusion: always remove all dir,file attributes diffrent then Normal before deleting. So below code solve the problem:
System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(#"E:\3\{90120000-0021-0000-0000-0000000FF1CE}-C1");
if (dir.Exists)
{
setAttributesNormal(dir);
dir.Delete(true);
}
. . .
function setAttributesNormal(DirectoryInfo dir) {
foreach (var subDir in dir.GetDirectories())
setAttributesNormal(subDir);
foreach (var file in dir.GetFiles())
{
file.Attributes = FileAttributes.Normal;
}
}
I used binball's code and added one line to set the directory attributes to normal also.
if (dir.Exists)
{
setAttributesNormal(dir);
dir.Delete(true);
}
function setAttributesNormal(DirectoryInfo dir)
{
foreach (var subDir in dir.GetDirectories())
{
setAttributesNormal(subDir);
subDir.Attributes = FileAttributes.Normal;
}
foreach (var file in dir.GetFiles())
{
file.Attributes = FileAttributes.Normal;
}
}
Based on the directory you are working in, you will probably need administrator access to delete files. To test this, run your app as administrator from explorer and see if it works (right-click the .exe and choose "Run As Administrator").
If that works, you'll need to get administrator privileges when your application executes. You can do this by adding the following to your application manifest:
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="requireAdministrator" />
</requestedPrivileges>
</security>
</trustInfo>
Adding to #binball and #Chuck answer. Here is a somewhat quick async-friendly implementation of setAttributesNormal() using BFS to traverse directories.
It's ideal for deep directory traversal, where recursion may fill call stack.
internal static void SetAttributesNormal(DirectoryInfo path) {
// BFS folder permissions normalizer
Queue<DirectoryInfo> dirs = new Queue<DirectoryInfo>();
dirs.Enqueue(path);
while (dirs.Count > 0) {
var dir = dirs.Dequeue();
dir.Attributes = FileAttributes.Normal;
Parallel.ForEach(dir.EnumerateFiles(), e => e.Attributes = FileAttributes.Normal);
foreach (var subDir in dir.GetDirectories())
dirs.Enqueue(subDir);
}
}
Have you tried to create a new instance of the DirectoryInfo class, and then checking the exists before the delete? The code would look like this:
System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(#"E:\3\{90120000-001A-0000-0000-0000000FF1CE}-C");
if (dir.Exists)
dir.Delete(true);
Also, please verify that you (the user running the application) has access to the folder. If this is a network mapped drive, it will need to be able to be deleted by the user running the application.
Hope this helps!
I had this symptom, and it actually was explorer.exe itself that was locking the directory. I found this using handle.exe, but one can also use powershell to find which process is locking the file:
$lockedFile = "C:\Windows\System32\wshtcpip.dll"
Get-Process | foreach{$processVar = $_; $_.Modules | foreach { if ($_.FileName -like "${lockedFile}*") { $processVar.Name + " PID:" + $processVar.id + " [" + $_.Filename + "]"}}}
You then have to decide whether to try to stop that process gracefully or not; it would be easy to modify the powershell script to try to kill any processes locking the file:
$lockedFile = "C:\directory_I_want_to_delete"
Get-Process | foreach{$processVar = $_; $_.Modules | foreach { if ($_.FileName -like "${lockedFile}*") { write-host $processVar.Name + " PID:" + $processVar.id + " [" + $_.Filename + "]" ; write-host "Killing process..." ; stop-process -pid $processVar.id -force }}}