We are migrating data from one filer to another and we have home directories setup for a bunch of users under their Active Directory profile. Some users have \\\x.x.x.x\sharename\etc, some have \\\hostname\sharename\etc and some have \\\hostname.domain.global\sharename\etc.
I need to replace the first portion of x.x.x.x, hostname and hostname.domain.global with the new DFS name of domain.global\sharename\etc, leaving everything else the same.
How can I go about doing this?
Thank you.
You should be able to use regular expressions. Examples:
PS C:\> '\\1.2.3.4\sharename1\etc1' |
Select-String '^\\\\[^\\]+\\(.+)' |
ForEach-Object { "\\domain.global\{0}" -f $_.Matches[0].Groups[1].Value }
\\domain.global\sharename1\etc1
PS C:\> '\\hostname\sharename2\etc2' |
Select-String '^\\\\[^\\]+\\(.+)' |
ForEach-Object { "\\domain.global\{0}" -f $_.Matches[0].Groups[1].Value }
\\domain.global\sharename2\etc2
PS C:\> '\\hostname.domain.global\sharename3\etc3' |
Select-String '^\\\\[^\\]+\\(.+)' |
ForEach-Object { "\\domain.global\{0}" -f $_.Matches[0].Groups[1].Value }
\\domain.global\sharename3\etc3
The regular expression pattern is:
^\\\\[^\\]+\\(.+)
This translates to: Start with (^) two \ characters, get 1 or more characters that are not \, followed by a single \, and then one or more characters (.+). The ( ) capture the path portion and make it available in the string replacement (i.e., $_.Matches[0].Groups[1].Value).
Related
Sorry in advance for the probably trivial question, I'm a powershell noob, please bear with me and give me advice on how to get better.
I want to achieve a file index index.txt that contains the list of all files in current dir and subdirs in this format:
./dir1/file1.txt 07.05.2020 16:16 1959281
where
dirs listed are relative (i.e. this will be run remotely and to save space, the relative path is good enough)
the delimiter is a tab \t
the date format is day.month.fullyear hours:minutes:seconds, last written (this is the case for me, but I'm guessing this would be different on system setting and should be enforced)
(the last number is the size in bytes)
I almost get there using this command in powershell (maybe that's useful to someone else as well):
get-childitem . -recurse | select fullname,LastWriteTime,Length | Out-File index.txt
with this result
FullName LastWriteTime Length
-------- ------------- ------
C:\Users\user1\Downloads\test\asdf.txt 07.05.2020 16:19:29 1490
C:\Users\user1\Downloads\test\dirtree.txt 07.05.2020 16:08:44 0
C:\Users\user1\Downloads\test\index.txt 07.05.2020 16:29:01 0
C:\Users\user1\Downloads\test\test.txt 07.05.2020 16:01:23 814
C:\Users\user1\Downloads\test\text2.txt 07.05.2020 15:55:45 1346
So the questions that remain are: How to...
get rid of the headers?
enforce this date format?
tab delimit everything?
get control of what newline character is used (\n or \r or both)?
Another approach could be this:
$StartDirectory = Get-Location
Get-ChildItem -Path $StartDirectory -recurse |
Select-Object -Property #{Name='RelPath';Expression={$_.FullName.toString() -replace [REGEX]::Escape($StartDirectory.ToString()),'.'}},
#{Name='LastWriteTime';Expression={$_.LastWriteTime.toString('dd.MM.yyyy HH:mm:ss')}},
Length |
Export-Csv -Path Result.csv -NoTypeInformation -Delimiter "`t"
I recommend to use proper CSV files if you have structured data like this. The resulting CSV file will be saved in the current working directory.
If the path you are running this from is NOT the current scrip path, do:
$path = 'D:\Downloads' # 'X:\SomeFolder\SomeWhere'
Set-Location $path
first.
Next, this ought to do it:
Get-ChildItem . -Recurse -File | ForEach-Object {
"{0}`t{1:dd.MM.yyyy HH:mm}`t{2}" -f ($_ | Resolve-Path -Relative), $_.LastWriteTime, $_.Length
} | Out-File 'index.txt'
On Windows the newline will be \r\n (CRLF)
If you want control over that, this should do:
$newline = "`n" # for example
# capture the lines as string array in variable $lines
$lines = Get-ChildItem . -Recurse -File | ForEach-Object {
"{0}`t{1:dd.MM.yyyy HH:mm}`t{2}" -f ($_ | Resolve-Path -Relative), $_.LastWriteTime, $_.Length
}
# join the array with the chosen newline and save to file
$lines -join $newline | Out-File 'index.txt' -NoNewline
Because your requirement is to NOT have column headers in the output file, I'm using Out-File here instead of Export-Csv
When calling
Get-PsDrive | Select Name,Root
I can see the followng drives:
Name Root
---- ----
Alias
C C:\
Cert \
Env
Function
G \\company.com\EVP\Data\Gen...
HKCU HKEY_CURRENT_USER
HKLM HKEY_LOCAL_MACHINE
Variable
WSMan
X \\server\C$
Z \\server\C$
Great. Now I only want the network drives, ie drives where Root contains \\ and Provider is FileSystem.
So I tried
Get-PSDrive |
where {$_.Provider -match "FileSystem" -and $_.Root -match "\\"}
| Select -ExpandProperty Name
But this includes the C drive for some reason. How is that possible?
I also tried changing to
$_.Root -match "\\\"
But I get
parsing "\\" - Illegal \ at end of pattern.
and
$_.Root -match "\\\\"
returns nothing.
-match takes a regular expression (regex) on the right, and in regular expression language a backslash is an escape character, and the way to specify a backslash is to escape it with another one - i.e. \\ translates to a single backslash, which matches drives like C:\.
Your options are:
$_ -match '\\\\' # two escaped backslashes
$_ -match [regex]::Escape('\\') # it returns \\\\ but maybe clearer to a reader what's happening
$_.StartsWith('\\') # don't use a regex, use a .Net string method
Edit:
As I mentioned in my question, when trying to -match with '\\', I get no return value.
Run Get-PsDrive Z | Format-List -Property * and see something like:
Used : 89738715136
Free : 29716107264
CurrentLocation :
Name : Z
Provider : Microsoft.PowerShell.Core\FileSystem
Root : Z:\
Description :
MaximumSize :
Credential : System.Management.Automation.PSCredential
DisplayRoot : \\localhost\c$
and it shows that the property root is really the drive letter, and the UNC path is called DisplayRoot. I don't know why, but it looks like the output formatting system is showing the DisplayRoot value and presenting it as the Root value. But that's just happening at the final presentation step, you can't use it in your script.
#Lieven Keersmaekers' suggestion of using $_.DisplayRoot -match '\\\\' is good.
In a directory there will be 2 type of files with same name but different extension for eg:1.png , 1.txt, test_76.png,test_76.txt, test_70.png. In this case test_70.png dosent have its .txt counterpart.I am using this code
$scL = dir *.txt | select Basename
$SList = #($scL -notmatch "MICRO")
$pList = dir *.png | select Basename
$PList = #($pList -notmatch "MICRO")
Compare-Object $PList $SList | ForEach-Object {$_.InputObject} | out-file result.txt
but i am unable to get the desired output that is test_70.png in the output file.Also i want to wrap the output inside the text file in double quotes i.e; the outfile should contain entry like this "test_70.png". Can anyone throw light on what am i missing in the compare-object cmdlet.
Your InputObject is a file object so you will need to access the name. Also in Powershell you can access the properties of the the items in a collection directly. Something like this:
(Compare-Object $PList $SList).InputObject.Name | % {"`"$_`""} | Out-File result.txt
Say I have following file structure
L:\Enterprise\Legal\Planning\Contacts\A-D\
Under A-D I have 50 Folders which is named after company name. So it looks like this
L:\Enterprise\Legal\Planning\Contacts\A-D\3-M Company\subfolder\sub-subfolder\files.txt
L:\Enterprise\Legal\Planning\Contacts\A-D\ABC Company\subfolder\sub-subfolder\files.txt
L:\Enterprise\Legal\Planning\Contacts\A-D\XYZ Company\subfolder\sub-subfolder\files.txt
L:\Enterprise\Legal\Planning\Contacts\A-D\AAA Company\subfolder\sub-subfolder\files.txt
Is there a way to get the company name from the above file structure using powershell or some windows script?
if your goal is to have a list of company name one way is:
cd L:\Enterprise\Legal\Planning\Contacts\A-D\
dir | select -expand fullname | % { ($_ -split '\\')[6] }
Some people may also find that this works instead
dir | select -expand fullname | % { ($_ -split '\\')[7] }
If you are importing a list of files/folders from a CSV, you could do this:
$strings = Import-CSV -Path "C:\PathToCSV.csv"
foreach ($string in $strings) {
$string -replace 'L:\\Enterprise\\Legal\\Planning\\Contacts\\A-D\\' -replace '\\subfolder\\sub-subfolder\\files.txt'
}
Note the double-slashes (\\). You have to escape the slashes, otherwise they are treated as special. Output should look like:
3-M Company
ABC Company
XYZ Company
AAA Company
What command in Powershell replaces grep -o (which displays only the matched portion of a line instead of a whole line) ?
i try use Select-Object but it always display full line.
For example:
next line
<a id="tm_param1_text1_item_1" class="tm_param1param2_param3 xxx_zzz qqq_rrrr_www_vv_no_empty" >eeee <span id="ttt_xxx_zzz">0</span></a>
use next command:
cat filename | grep -o '>[0-9]' | grep -o '[0-9]'
output: 0
When i use Select-Object i always see full line (
One way is:
$a = '<a id="tm_param1_text1_item_1" class="tm_param1param2_param3 xxx_zzz qqq_rrrr_www_vv_no_empty" >eeee <span id="ttt_xxx_zzz">0</span></a>'
$a -match '>([0-9])<' #returns true and populate the $matches automatic variable
$matches[1] #returns 0
For selecting strings in text, use select-string rather than select-object. It will return a MatchInfo object. You can access the matches by querying the matches property:
$a = '<a id="tm_param1_text1_item_1" class="tm_param1param2_param3 xxx_zzz qqq_rrrr_www_vv_no_empty" >eeee <span id="ttt_xxx_zzz">0</span></a>'
($a | select-string '>[0-9]').matches[0].value # returns >0
InPowerShell v3:
sls .\filename -pattern '^[0-9]' -AllMatches | % matches | % value
Explanation:
sls is an alias for Select-String. It takes a filename/path as well as a pattern as parameters. It produces "matches"
% matches selects all matches regardless of file etc.
% value selects the value of each match
The solutions that have been proposed so far only produce the first match from each line. To fully emulate the behavior of grep -o (which produces every match from each line) something like this is required:
Get-Content filename | Select-String '>([0-9])' -AllMatches |
Select-Object -Expand Matches | % { $_.Groups[1].Value }
Select-String -AllMatches returns all matches from an input string.
Select-Object -Expand Matches "disconnects" matches from the same line, so that all submatches can be selected via $_.Groups[1]. Without this expansion the submatch from the second match of a line would be $_.Groups[3].