I don't understand why ( is missing?
if not exist ("C:\test") md "C:\test"
At line:1 char:3
+ if not exist ("C:\test") md "C:\test"
+ ~
Missing '(' after 'if' in if statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingOpenParenthesisInIfStatement
Building on the helpful comments:
You're trying to use cmd.exe's syntax directly from PowerShell, which cannot work (given PowerShell's fundamentally different syntax) and causes the parsing error you saw.
Use the PowerShell equivalent of your cmd.exe call, via New-Item:
# Create directory C:\test or use a preexisting directory with that path
# (thanks to -Force).
# A DirectoryInfo object describing the directory is returned,
# which $null = ... discards.
$null = New-Item -Type Directory -Force C:\test
Related
I have been trying to get the audit settings from files and folders in Windows.
I need to validate for several different folders and files on Windows that the "Everyone" group has "Failure" flag checked for certain types of access attempts. I want to be able to show this using PowerShell instead of logging into each endpoint and opening each folders' properties -> advanced -> Auditing tab and taking screenshots for evidence if that's possible.
PowerShell Script
# Input file containing a list of folders
$folderListFile = ".\folder_list.txt"
# Read the folder list file into an array
$folderList = Get-Content $folderListFile
# Loop through each folder in the list
foreach ($folderPath in $folderList) {
# Get the audit flags for the folder
$auditFlags = (Get-Acl $folderPath).Audit
# Write the audit flags to the console
Write-Output "Folder Path: $folderPath"
Write-Output "Audit Flags: $($auditFlags.AuditToString())"
Write-Output ""
}
Contents of ".\folder_list.txt"
C:\
C:\Windows
C:\Windows\System32
Output:
PS P:\Scripts> .\Get-FolderAuditSettings.ps1
Folder Path: C:\
You cannot call a method on a null-valued expression.
At P:\Scripts\Get-FolderAuditSettings.ps1:14 char:32
+ Write-Output "Audit Flags: $($auditFlags.AuditToString())"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Audit Flags:
Folder Path: C:\Windows
You cannot call a method on a null-valued expression.
At P:\Scripts\Get-FolderAuditSettings.ps1:14 char:32
+ Write-Output "Audit Flags: $($auditFlags.AuditToString())"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Audit Flags:
Folder Path: C:\Windows\System32
You cannot call a method on a null-valued expression.
At P:\Scripts\Get-FolderAuditSettings.ps1:14 char:32
+ Write-Output "Audit Flags: $($auditFlags.AuditToString())"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
I figured it out!
I had to add the -Audit flag to the Get-ACL module
Now it returns an object of type: System.Security.AccessControl.FileSystemAuditRule
I then reference the properties listed for this object.
Reference: dotnet-api-system.security.accesscontrol
# Input file containing a list of folders
$folderListFile = ".\folder_list.txt"
# Read the folder list file into an array
$folderList = Get-Content $folderListFile
# Loop through each folder in the list
foreach ($folderPath in $folderList) {
# Get the audit flags for the folder
$auditFlags = (Get-Acl $folderPath -Audit).Audit
# Write the audit flags to the console
Write-Output "Folder Path: $folderPath"
Write-Output "Audit Identity: $($auditFlags.IdentityReference)"
Write-Output "Audit Rights: $($auditFlags.FileSystemRights)"
Write-Output "Audit Flags: $($auditFlags.AuditFlags)"
Write-Output ""
}
I put together this script over 5 years ago now and since have forgotten what I did or how I did it...
For some context, the below script which runs from a .bat file was used to enter a user's display name and then using dsquery and dsget, along with Get-Content from PowerShell commands. About 6 months ago this script stopped working and just crashes and fails with a brief error that it getting stuck on this line to my understanding:
dsquery user forestroot -name "%lookforuser%">"%userprofile%\Desktop\usertemp.txt"
The %lookforuser% variable is set earlier in the script, see below for full source code:
#echo off
title Get AD Groups For User
set /p lookforuser=Enter Username (Surname, Firstname):
set lookforuser2=%lookforuser: =%
echo %lookforuser%
echo %lookforuser2%
dsquery user forestroot -name "%lookforuser%">"%userprofile%\Desktop\usertemp.txt"
set /p usercn=<"%userprofile%\Desktop\usertemp.txt"
dsget user %usercn% -memberof>"%userprofile%\Desktop\usertemp.txt"
Powershell -Command "(Get-Content %userprofile%\Desktop\usertemp.txt) -replace '\"CN=','' ^| Out-File -encoding ASCII %userprofile%\Desktop\usertemp.txt"
Powershell -Command "(Get-Content %userprofile%\Desktop\usertemp.txt) -replace ',OU=','*' | Out-File -encoding ASCII %userprofile%\Desktop\usertemp.txt"
for /f "delims=*, tokens=1" %%A IN (%userprofile%\Desktop\usertemp.txt) do echo %%A>>"%userprofile%\Desktop\%lookforuser2%.txt"
del "%userprofile%\Desktop\usertemp.txt"
Long story short, can anyone help me figure out what's gone on, has my parent company changed something to force this not to work, or has MS changed something that no longer allows this script to run, really stumped and not sure.
Any help would be greatly appreciated, even if you have something similar that works in Powershell
Please see error in command prompt below:
Get-Content : Cannot find path 'C:\Users\mcguirkd\Desktop\usertemp.txt' because it does not exist.
At line:1 char:2
+ (Get-Content C:\Users\mcguirkd\Desktop\usertemp.txt) -replace '"CN=', ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\Users\mcguirkd\Desktop\usertemp.txt:String) [Get-Content], ItemNotFo
undException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand
Out-File : Could not find a part of the path 'C:\Users\mcguirkd\Desktop\usertemp.txt'.
At line:1 char:75
+ ... '"CN=','' | Out-File -encoding ASCII C:\Users\mcguirkd\Desktop\userte ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OpenError: (:) [Out-File], DirectoryNotFoundException
+ FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.OutFileCommand
Get-Content : Cannot find path 'C:\Users\mcguirkd\Desktop\usertemp.txt' because it does not exist.
At line:1 char:2
+ (Get-Content C:\Users\mcguirkd\Desktop\usertemp.txt) -replace ',OU=', ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\Users\mcguirkd\Desktop\usertemp.txt:String) [Get-Content], ItemNotFo
undException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand
Out-File : Could not find a part of the path 'C:\Users\mcguirkd\Desktop\usertemp.txt'.
At line:1 char:76
+ ... ,OU=','*' | Out-File -encoding ASCII C:\Users\mcguirkd\Desktop\userte ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OpenError: (:) [Out-File], DirectoryNotFoundException
+ FullyQualifiedErrorId : FileOpenFailure,Microsoft.PowerShell.Commands.OutFileCommand
I modified PowerShell script from PowerShell - Batch change files encoding To UTF-8.
# Modified version of https://stackoverflow.com/q/18684793
[Threading.Thread]::CurrentThread.CurrentUICulture = 'en-US'
$Encoding = New-Object System.Text.UTF8Encoding($True) # If UTF8Encoding($False), It will be UTF-8 without BOM
$source = "C:\Users\AKULA\Desktop\SRC" # source directory
$destination = "C:\Users\AKULA\Desktop\DST" # destination directory
if (!(Test-Path $destination)) {
New-Item -Path $destination -ItemType Directory | Out-Null
}
# Delete all previously generated file
Get-ChildItem -Path $destination -Include * -File -Recurse | ForEach-Object {$_.Delete()}
# Recursively convert all files into UTF-8
foreach ($i in Get-ChildItem $source -Force -Recurse -Exclude "desktop.ini") {
if ($i.PSIsContainer) {
continue
}
$name = $i.Fullname.Replace($source, $destination)
$content = Get-Content $i.Fullname
if ($null -ne $content) {
[System.IO.File]::WriteAllLines($name, $content, $Encoding)
} else {
Write-Host "No content from: $i"
}
}
But after using it, I've found that PS cannot handle [ or ] well.
I made some test files that has diversity in name/content.
Get-Content : An object at the specified path C:\Users\AKULA\Desktop\SRC\FILENAME[[[[[[]]]]]]]].txt does not exist, or
has been filtered by the -Include or -Exclude parameter.
At C:\Users\AKULA\Desktop\Convert_to_UTF-8.ps1:24 char:16
+ $content = Get-Content $i.Fullname
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (System.String[]:String[]) [Get-Content], Exception
+ FullyQualifiedErrorId : ItemNotFound,Microsoft.PowerShell.Commands.GetContentCommand
Since I cannot embed images in question, here is link of IMGUR album.
Full image list: https://imgur.com/a/aN1RG2L
These are what I've tested:
Test files have different names. Their name contains space, ',
[]. Also made up different language(Japanese, Korean).
These files have same content, encoded with UCS-2 BE BOM(UTF-16 BE) so
that I can check if it has re-encoded to UTF-8.
How can I make my script handle [ or ] in file name well?
tl;dr
Indeed, use of the -LiteralPath parameter is the best solution (in PowerShell (Core) v6+, you can shorten to -lp):
$content = Get-Content -LiteralPath $i.Fullname
-LiteralPath ensures that $i.Fullname is taken verbatim (literally); that is, [ and ] in the path are interpreted as themselves rather than having special meaning, as they would have as a -Path argument, due to being interpreted as a wildcard expression - note that -Path is positionally implied if you only pass a value (a string) as the first argument, as you did (Get-Content $i.FullName)
Note: This answer analogously applies to all cmdlets that have both -Path and -LiteralPath parameters, such as Set-Content, Out-File, and Set-Location.
As for what you tried:
$content = Get-Content $i.Fullname
is effectively the same as:
$content = Get-Content -Path $i.Fullname
That is, the (first) positional argument passed to Get-Content is implicitly bound to the
-Path parameter.
The -Path parameter accepts wildcard expressions to allow matching paths by patterns; in addition to support for * (any run of characters) and ? (exactly 1 character), [...] inside a wildcard pattern denotes a character set or range (e.g., [12] or [0-9]).
Therefore an actual path that contains [...], e.g., foo[10].txt, is not recognized as such, because the [10] is interpreted as a character set matching a single character that is either 1 or 0; that is foo[10].txt would match foo0.txt and foo1.txt, but not a file literally named foo[10].txt.
When (implicitly) using -Path, it is possible to escape [ and ] instances that should be interpreted verbatim, namely via the backtick (`), but note that this can get tricky to get right when quoting and/or variable references are involved.
If you know a path to be a literal path, it is best to form a habit of using -LiteralPath (which in PowerShell Core you can shorten to -lp).
However, if your path contains literal [ and ] and you also need wildcard matching, you must use `-escaping - see this answer.
There are at least two situations where the solution's good advice doesn't hold, unfortunately.
Selective error handling
Get-Content -LiteralPath "nobox[]" gives an error message and exception type as if wildcards are involved:
Get-Content : An object at the specified path box[] does not exist, or has been filtered by the -Include or -Exclude parameter.
At line:1 char:1
+ Get-Content -Path "nobox[]"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (System.String[]:String[]) [Get-Content], Exception
+ FullyQualifiedErrorId : ItemNotFound,Microsoft.PowerShell.Commands.GetContentCommand
whereas without the brackets, we get:
Get-Content : Cannot find path 'nobox' because it does not exist.
At line:1 char:1
+ Get-Content -LiteralPath "nobox"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (nobox:String) [Get-Content], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetContentCommand
Therefore, to silently deal with an optional file, something like:
try {
$lines = Get-Content -LiteralPath $path -ErrorAction Stop
}
catch [System.Management.Automation.ItemNotFoundException] {
$lines = #()
}
chokes on paths with brackets.
Creating a hard or symbolic link
A minor and a major caveat:
The Path parameter, the name of the new item, "works like the LiteralPath parameter of other cmdlets", says the documentation of New-Item clearly, and that seems true and makes sense. Though I wish we could clarify that by writing -LiteralPath.
The Value parameter, the target of the link (also known as Target secretly in v5 and openly later), does not accept wildcard characters according to the same documentation, but that's a lie. The command:
New-Item -ItemType "HardLink" -Path "whatever" -Target "*"
makes Powershell squeal "Cannot set the location because path '*' resolved to multiple containers.".
So you always need the escapes for the target. If you have a file named "f[]", then this will display an error:
New-Item -ItemType "HardLink" -Path "whatever" -Target "f[]"
and this will create a link:
New-Item -ItemType "HardLink" -Path "f[2]" -Target ([WildcardPattern]::Escape("f[]"))
Same for ItemType "SymbolicLink".
Since you can only view the C:\$RECYCLE.BIN Folder when you uncheck (Hide protected Operating System Files) you can't change the date modified through the usual way with PowerShell:
$file = Get-Item C:\Path\TO\File.txt
$file.LastWriteTime = (Get-Date)
or
$folder = Get-Item C:\folder1
$folder.LastWriteTime = (Get-Date)
When calling Get-Item C:\$RECYCLE.BIN, I get the following error:
Get-Item : Cannot find path 'C:\.bin' because it does not exist.
At line:1 char:9
+ $file = Get-Item C:\$Recycle.bin
+ ~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\.bin:String) [Get-Item], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand
How would I go about changing the date modified of it?
As C:\$RECYCLE.BIN contains $, PowerShell tries to evaluate the variable $RECYCLE, which is empty. Thus, the resulting path C:\.bin cannot be found. Quote your path with single quotes (') to prevent PowerShell from evaluating your string and also add the -Force parameter as it is a system directory:
Get-Item -Path 'C:\$RECYCLE.BIN' -Force
You can then access your files and change the LastWriteTime as you already tried in your question:
$fileObject = Get-Item -Path 'C:\$RECYCLE.BIN\S-1-5-21-3323847664-626704455-790384891-1001\$RT8USDF.txt' -Force
$fileObject.LastWriteTime = Get-Date
Does anyone have any idea why Remove-Item would fail while Delete works?
In below script, I get a list of files I'd like to delete.
Using Remove-Item I get following error message:
VERBOSE: Performing the operation "Remove File" on target
"\\UncPath\Folder\test.rtf". Remove-Item : Cannot remove item
\\UncPath\Folder\test.rtf: Access to the path is denied.
but using Delete is deleting those files as we speak.
Script
$files = gci \\UncPath\Folder| ?{ $_.LastWriteTime -le (Get-Date).addDays(-28) }
# This doesn't work
$files | Remove-Item -force -verbose
# But this does
$files | % { $_.Delete() }
powershell may act strange with UNC path, I think it prepends the UNC Path with the current provider you can verify this with :
cd c:
test-path \\127.0.0.1\c$
returns TRUE
cd HKCU:
test-path \\127.0.0.1\c$
returns FALSE
when specifying the fullpath we're telling powershell to use the filesystem provider, that solves the problem. you could also specify the provider like remove-item filesystem::\\uncpath\folder
I can finally repro this and IMO it appears to be a bug. The repro is to have an open share like C$ but to set Deny Modify perms for the user on the file. When I do that, I observe this:
PS> gci '\\Keith-PC\C$\Users\Keith\foo.txt' | ri -for
ri : Cannot remove item \\Keith-PC\C$\Users\Keith\foo.txt: Access to the path is denied.
At line:1 char:43
+ gci '\\Keith-PC\C$\Users\Keith\foo.txt' | ri -for
+ ~~~~~~~
+ CategoryInfo : InvalidArgument: (\\Keith-PC\C$\Users\Keith\foo.txt:FileInfo) [Remove-Item], ArgumentExc
eption
+ FullyQualifiedErrorId : RemoveFileSystemItemArgumentError,Microsoft.PowerShell.Commands.RemoveItemCommand
PS> gci '\\Keith-PC\C$\Users\Keith\foo.txt' | %{$_.Delete()} # <== this works!
I also observe that removing the -Force parameter deletes the file without error as well. The deny perms still allow me to delete the file from Windows Explorer so that leads me to believe that the file should delete. So what is up with using the -Force parameter? When I delve into the ErrorRecord I see this:
Message : Access to the path is denied.
ParamName :
Data : {}
InnerException :
TargetSite : Void set_Attributes(System.IO.FileAttributes)
StackTrace : at System.IO.FileSystemInfo.set_Attributes(FileAttributes value)
at Microsoft.PowerShell.Commands.FileSystemProvider.RemoveFileSystemItem(FileSystemInfo
fileSystemInfo, Boolean force)
It seems that the -Force parameter is trying to set (more likely reset) attributes and the permissions on the file don't allow it e.g.:
PS> gci '\\Keith-PC\C$\Users\Keith\foo.txt' | %{$_.Attributes = 'Normal'}
Exception setting "Attributes": "Access to the path is denied."
At line:1 char:45
+ gci '\\Keith-PC\C$\Users\Keith\foo.txt' | %{$_.Attributes = 'Normal'}
+ ~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], SetValueInvocationException
+ FullyQualifiedErrorId : ExceptionWhenSetting
So it seems to me that PowerShell should first try as if the -Force weren't present and if that fails, then try resetting attributes.