Where in the world is complete documentation for PowerShell scripting? - powershell

I started doing some powershell scripting today for my work and I can find this page: http://technet.microsoft.com/en-us/library/hh849827.aspx
This shows all the Cmdlets that I am using in the scripts, but I cannot find the documentation on how to use the returned objects of these Cmdlets. For example, I am using the Get-ChildItem cmd to get all the files in a dir recursively. Then I am using a ForEach loop like this:
$dest = "C:\Users\a-mahint\Documents\Testing\Dest"
$destlist = Get-ChildItem $dest -Recurse
foreach ($file in $destlist){
write-host "File: $file"
write-host $file
$result = test-path -path "C:\Users\a-mahint\Documents\Testing\Src\*" -include $file.Name
if (-not $result){
Copy-Item $file -Destination "$backup"
}
}
write-host "Done copying deleted files"
Except I have no idea what type of object a $file is...In the documentation above, it just says it outputs a System.Object, but that doesn't help at all. I want to know all the properties of this object so I can use them to debug.

From a question I asked one time Andy Arismendi supplied some links for me to read.
You can download said specification: 2.0 and 3.0.
$file = Get-Item C:\foo.txt
Remember there is a $file | Get-Member command you can use to view the objects methods and properties. Also since everything in PowerShell is an Object you can always do $file.GetType() and then Bing that type.

Get-ChildItem "C:\Windows\System32\WindowsPowerShell\v1.0\en-US" -Filter *.txt

Here is a decent reference for get-childitem.
http://technet.microsoft.com/en-us/library/ee176841.aspx
What kind of file details are you needing exactly?

Related

Map an app to all folders/files in a directory recursively

I'm hoping to use Powershell to:
Recurse through directories, of various depths, with the current PS
script's directory being root
Apply an app to those directories (which in turn will process the files within it)
Which also requires an input of a new subdir to make base
The command I want to apply to each directory takes the format:
c:\xrv\fileprocess.exe -folderIn [dir] -foldorOut [newdir]
I'm at a bit of a loss on how to make this happen. I've tried to hash together something from snippets online but I never seem to have success. I've kind of made a part hodgepodge snippet part pseudo code attempt to explain what I'm trying to do below.
I'd also note that the paths are looong!
Thanks all!
Clear-Host
$StartDirectory = '\.'
echo $StartDirectory
$files = Get-ChildItem -LiteralPath $StartDirectory -Recurse -Directory `|
foreach($dir in $dirs){
c:\xrv\fileprocess.exe -folderIn $dir -foldorOut "$dir\pd"
}
I have tried to not change too much from your code. try this:
if the $dir\pd dosent exist, does the program create it? if not then you would have to include a mkdir $dir\pd inside the foreach loop.
Clear-Host
$StartDirectory = '\.'
$exe = 'c:\xrv\fileprocess.exe'
Write-Host $StartDirectory
$dirs = Get-ChildItem -LiteralPath $StartDirectory -Recurse -Directory
foreach ($dir in $dirs)
{
&$exe -folderIn $dir -foldorOut "$dir\pd"
}

Powershell Script Check if folder doesnt contain random file other than specific file, It will Create New File

Im quite new to powershell script. Currently I wan to find the files in the path, if the path doesnt contain .txt file, it will create a new text file. Is there anyway i can do that?
I've tried with script below but it came out with the error parameter eq not found
if (Test-Path $path -Exclude *.bak -eq false)
We can use Get-ChilItem as our base here and pass the properties we are searching for such as the the .txt extension and do something with it. Using the if conditional statement, we can accomplish this like so:
#assign the objects returned from Get-ChildItem to $loc
$Loc = Get-ChildItem C:\users\Abraham
#Check to see if the extension is found using a -notcontains conditional operator
#(against the property of .extension of each returned object (paths))
#See here https://www.computerperformance.co.uk/powershell/contains/
if($Loc.extension -notcontains ".txt"){
#this is our "DO", where the condition was met above
#so we will create the text file named "MyText"
#(by passing the "fullname" property which contains the full path of the objects in $Loc.)
New-Item -Path $Loc.fullname -Name MyText.txt}
What we're doing here is referencing the properties of the returned objects from Get-ChildItem by using whats called, "Dot Notation": $loc.Name, $loc.fullname, $loc.LastWriteTime, etc
You can get a list of the properties and methods(stuff you can do to the object(s)) by piping any cmdlet to Get-Member. Get-ChildItem | GM #GM is an alias for Get-Member.
Do you mean you want to use Test-Path to check if a certain file is present and if not create it?
Something like this then perhaps?
$path = 'D:\Test'
if (!(Test-Path -Path "$path\*" -Filter '*.txt' -PathType Leaf)) {
$null = New-Item -Path $path -Name ('Test_{0:ddMMyyyy}.txt' -f (Get-Date))
}

Define folder depth for the verbose option in Copy-Item cmdlet

I'm using the following command to copy a directory tree from one folder to another.
Copy-Item $SOURCE $DEST -Filter {PSIsContainer} -Recurse -Force -Verbose
The verbose option is correctly showing each folder that is copied. However, I would like to tell the Verbose option to only shows the first level of the subfolders that are copied. Hence the subfolders/subfolders/... etc wouldn't appear.
Is it possible?
Instead of using the -Verbose option, you could use the -PassThru option to process the successfully processed items via the pipeline. In the following example, I am assuming that $DEST is the existing directory in which the newly copied directory will appear. (You cannot call Get-Item on non-existant objects.)
$SOURCE = Get-Item "foo"
$DEST = Get-Item "bar"
Copy-Item $SOURCE $DEST -Filter {PSIsContainer} -Recurse -Force -PassThru | Where-Object {
# Get the parent object. The required member is different between
# files and directories, which makes this a bit more complex than it
# might have been.
if ($_.GetType().Name -eq "DirectoryInfo") {
$directory = $_.Parent
} else {
$directory = $_.Directory
}
# Select objects as required, in this case only allow through
# objects where the second level parent is the pre-existing target
# directory.
$directory.Parent.FullName -eq $DEST.FullName
}
Count the number of backslashes in the path and add logic to select first level only perhaps. Something like this perhaps?
$Dirs=get-childitem $Source -Recurse | ?{$_.PSIsContainer}
Foreach ($Dir in $Dirs){
$Level=([regex]::Match($Dir.FullName,"'b")).count
if ($Level -eq 1){Copy-Item $Dir $DEST -Force -Verbose}
else{Copy-Item $Dir $DEST -Force}}
*Edited to include looping and logic per requirements
I would suggest using robocopy instead of copy-item. Its /LEV:n switch sounds like it's exactly what you're looking for. Example (you'll need to test & tweak to meet your requirements):
robocopy $source $dest /LEV:2
robocopy has approximately 7 gazillion options you can specify to get some very useful and interesting behavior out of it.

Why is my PowerShell script writing blank lines to console?

I have a bit of an odd problem. Or maybe not so odd. I had to implement a "custom clean" for a PowerShell script developed for building some unique configurations for my current project (the whys are not particularly important). Basically it copies a bunch of files from the release directories into some temporary directories with this code:
$Paths = Get-ChildItem $ProjectPath -recurse |
Where-Object { ($_.PSIsContainer -eq $true) -and
(Test-Path($_.Fullname + 'bin\release')) } |
Select-Object Fullname
ForEach ($Path in $Paths)
{
$CopyPath = $Path.Fullname + '\bin\Temp'
$DeletePath = $Path.Fullname + '\bin\Release'
New-Item -ItemType directory -path $CopyPath
Copy-Item $DeletePath $CopyPath -recurse
Remove-Item $DeletePath Recurse
}
And after the build copies it back with:
ForEach ($Path in $Paths)
{
$CopiedPath = $Path.Fullname + '\bin\Temp\'
$DeletedPath = $Path.Fullname + '\bin\Release\'
$Files = Get-ChildItem $CopiedPath -recurse |
where-object {-not $_PSIsContainer}
ForEach ($File in $Files)
{
if(-not (Test-Path ($DeletedPath+$File.Name)))
{
Copy-Item $File.Fullname ($DeletedPath+$File.Name)
}
}
Remove-Item $CopyPath -recurse -force
}
This is pretty clunky and noobish (Sorry, I'm a PowerShell noob drinking from a fire hose), but it works for the purpose and I will clean it up later. However, when it executes the initial copy to the temp directories, it writes a lot of blank lines to the screen, which isn't ideal as I have a message I display while this process is executing to assure our CM doesn't freak out and think it broke, but this message is blown away by the blank lines. Do you know what might be causing this and how I might solve this? I'm using PowerShell 2.0 out of the box and due to the nature of this project I can't upgrade or get any outside libraries. Thanks guys.
If the only thing you're looking to do is clean up the console output, then all you need to do is use the pipeline. You can start the command with [void], which will exclude all information from the pipeline. You can also pipe the whole thing into the Out-Null cmdlet, which will trap all output, except for the lines that don't have output.
The New-Item cmdlet by default returns output to the console on my version of Windows PowerShell (4.0). This may not be true on previous versions, but I think it is... Remove-Item also doesn't return any output, usually. If I were to take a stab, I'd kill output on those lines that use the "Item" noun using one of the methods mentioned above.

Powershell Rename-Item issue with special characters

I've run into the issue I know has been addressed several times here previously but I'm not overly familiar with PS scripts or regular expressions and I'm struggling to implement a fix here.
Basically, I'd be very happy if this line of my script would work:
Get-childItem *.* -recurse -force | % {rename-item $_.name ($_.name -replace '(\d{2}) \[(\d{1})x(\d{2})\]','$1 s0$2e$3')}
And example file name would be "24 [1x01].avi" and should instead be named "24 s01e01.avi" - I'm trying to tidy up my media collection :)
I know the reason it doesn't is the square brackets in the file names. I think i have to move the files to a temp location, changing the name while doing so and then move back. My difficulty is that I haven't been able to find an example of this using the regular expression and I haven't been able to get this to work.
Also, is there a better workaround than this available yet? The bug on Microsoft Connect is closed as fixed?
Thanks!
I think your regular expressions might make more sense (to you), especially as a beginner, if you used "named groups" (a regular expression concept). I've modified your regular expression slightly to take this into account. You should really get familiar with regular expression terminology though, to ensure that you can update your regex to work in all scenarios.
"24 [1x01].avi" -replace '(?<ShowName>.*) \[(?<Season>\d{1})x(?<Episode>\d{2})\]','${ShowName} s0${Season}e${Episode}';
Result:
24 s01e01.avi
Can you give an example of a file name that doesn't work?
EDIT: Attaching example script. Let me know if this works for you.
# 1. Define a test folder path
$RootPath = "$env:SystemDrive\test";
# 2. Create the folder
mkdir -Path $RootPath;
# 3. Create a test file
Set-Content -Path "$RootPath\24 [1x01].txt" -Value '';
# 4. Get a list of files in the directory
$FileList = Get-ChildItem -Path $RootPath;
foreach ($File in $FileList) {
# 5. Fix up the name of each file
$NewName = $File.Name -replace '(?<ShowName>.*) \[(?<Season>\d{1})x(?<Episode>\d{2})\]','${ShowName} s0${Season}e${Episode}';
# 6. Rename the file
Move-Item -Path $File.FullName -Destination ((Split-Path -Path $File.FullName -Parent) + $NewName);
}
powershell Rename-Item fail to rename
If you are running PS 3+ add -LiteralPath switch to your rename:
One of the easiest ways to handle the Special Characters (such as square/block brackets[]) in the file-names, is to simply use the -LiteralPath parameter.
Error: When attempting to rename files or folders that contain square/block brackets [], the standard error message that PowerShell returns is "file not found", which is not accurate.
Reason: Windows still uses old fashioned 8.3 format short-file-names (max 8 chars with limited allowed chars) unfortunately PowerShell's -Path parameter (even in version 5.1) uses these internal names.
Solution: Use the -LiteralPath argument, available for most cmdlets (including Get-ChildItem or Rename-Item etc.)
Examples: Depicting handling of files or folders that contain square/block brackets []:
Get-ChildItem -LiteralPath "test[1].txt";
Test-Path -LiteralPath "C:\dir\test[1].txt";
Rename-Item -LiteralPath "test[1].txt" "test[2].txt";
Note: In PowerShell version below 3.0, to rename files/directories containing special characters, use Move-Item with -LiteralPath, instead of Rename-Item cmdlet because Rename-Item didn't have -LiteralPath in PS version 2.0 (or below).
Thanks to pointers from #Trevor Sullivan I was able to get the desired results by:
Updating to the most recent version of PowerShell (download link available in the comments)
Edited the script to the following:
Get-childItem *.* -recurse -force | Move-Item -Destination {$_ -replace '(\d{2}) \[(\d{1})x(\d{2})\]','$1 s0$2e$3'}