Get-Acl does not seem to work on UNC path? - windows

I have difficulty getting Get-Acl to work on a UNC path to get the share permissions of a directory and all underlying files and directories.
The code I use looks like this:
$OutFile = "C:\Users\xxxx\Desktop\Permissions.csv"
$Header = "Folder Path,IdentityReference,AccessControlType,IsInherited,InheritanceFlags,PropagationFlags,FileSystemRights"
del $OutFile
Add-Content -Value $Header -Path $OutFile
$RootPath = "\\intranet\sites\folder1\folder2\target-folder-as-root"
$Folders = dir $RootPath -Recurse
#| where {$_.psiscontainer -eq $true}-recurse
foreach ($Folder in $Folders) {
$ACLs = Get-Acl $Folder.Fullname | ForEach-Object { $_.Access }
foreach ($ACL in $ACLs) {
$OutInfo = $Folder.Fullname + "," + $ACL.IdentityReference + "," +
$ACL.AccessControlType + "," + $ACL.IsInherited + "," +
$ACL.InheritanceFlags + "," + $ACL.PropagationFlags + "," +
$ACL.FileSystemRights
Add-Content -Value $OutInfo -Path $OutFile
}
}
Not taking into account the filename size limit issue this might cause, I get the following error:
Get-Acl : Method failed with unexpected error code 1.
At C:\Users\xxxx\Documents\ntfs_permissions.ps1:12 char:10
+ $ACLs = Get-Acl $Folder.Fullname | ForEach-Object { $_.Access }
+ ~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Get-Acl], InvalidOperationException
+ FullyQualifiedErrorId : System.InvalidOperationException,Microsoft.PowerShell.Commands.GetAclCommand
I find documentation on listing the shared permissions on a shared drive using the UNC path (I don't want to list the permissions starting from the root, but only starting from a subfolder) is very limited.

Try to use: $ACLs = (Get-Acl $Folder.fullname).Access
Instead of: $ACLs = Get-Acl $Folder.Fullname | ForEach-Object { $_.Access }

Related

How to delete an image file based on its dimensions with PowerShell

I am trying to delete an image based on the dimensions of said image, but I've run into a problem.
I am trying to delete images whose length or width are less than 490 pixels. However, the code I have tried throws an error for every item. This is the error:
Remove-Item : Cannot remove item (file path): The process cannot access the file
'(file path)' because it is being used by another process.
At line:6 char:9
+ Remove-Item $_
+ ~~~~~~~~~~~~~~
+ CategoryInfo : WriteError: ((file path):FileInfo) [Remove-Item], IOException
+ FullyQualifiedErrorId : RemoveFileSystemItemIOError,Microsoft.PowerShell.Commands.RemoveItemCommand
Here is my code:
[Void][Reflection.Assembly]::LoadWithPartialName("System.Drawing")
$(Get-ChildItem -Filter *.jpg).FullName | ForEach-Object {
$img = [Drawing.Image]::FromFile($_);
If (($img.Width -lt 490) -or ($img.Height -lt 490)) {
Remove-Item $_
}
}
I am not running any apparent processes that would be using the images. When using Handle64, it says that powershell.exe is using the files. Any help would be appreciated!
The $img object is keeping the file in use, so you need to dispose of that before you can delete the file:
Add-Type -AssemblyName System.Drawing
(Get-ChildItem -Filter '*.jpg' -File).FullName | ForEach-Object {
$img = [System.Drawing.Image]::FromFile($_)
$w = $img.Width
$h = $img.Height
# get rid of the Image object and release the lock on the file
$img.Dispose()
If (($w -lt 490) -or ($h -lt 490)) {
Remove-Item -Path $_
}
}

Key not valid for use in specified state - A positional parameter cannot be found that accepts argument '+'

I am trying to understand what this error actually means. I am new to PowerShell and cannot
figure this one out. I have searched for similar questions but the content differs to my
requirement.
In a nut shell the script is queering a data historian system for a batch/lot number and the
start time of that batch.
This script will run every minute using task scheduler. This has not been set up yet as I am
still in the testing phase.
I have set up a service account is order for the script to run. The details of which are
stored in a cred file.
The script creates a folder using this batch/lot number.
The script creates a log file with the batch number and the start date and time of the batch.
Then the script searches a source folder on the server when a file is uploaded from the
factory floor into the source folder the script moves the file into the already created folder
with the correct batch number.
If files that are outside of the batch start and end time then the files are moved to no batch
folder where they will be reviewed manually.
I have done tests whereby I manually added files to the source folder on the server and
everything worked and did not get the "a positional parameter cannot be found that accepts
argument "+" from the script.
I am looking into the server configuration and permission levels but to my knowledge, nothing
has changed. I cannot see what is wrong with the script but hopefully, someone can give me
some pointers.
Error Code below
`PS C:\Users\a-graydx2> E:\Kistler Script\Batch ID with log 2021-11-29.ps1
An error occurred:
Key not valid for use in specified state.
Add-Content : A positional parameter cannot be found that accepts argument '+'.
At E:\Kistler Script\Batch ID with log 2021-11-29.ps1:186 char:11
+ Add-Content -Path $ErrorFileName -Value (Get-Date -Format " ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Add-Content], ParameterBindingException
+ FullyQualifiedErrorId :
PositionalParameterNotFound,Microsoft.PowerShell.Commands.AddContentCommand
An error occurred:
Key not valid for use in specified state.
Add-Content : A positional parameter cannot be found that accepts argument '+'.
At E:\Kistler Script\Batch ID with log 2021-11-29.ps1:186 char:11
+ Add-Content -Path $ErrorFileName -Value (Get-Date -Format " ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Add-Content], ParameterBindingException
+ FullyQualifiedErrorId :
PositionalParameterNotFound,Microsoft.PowerShell.Commands.AddContentCommand`
Script is below
Thanks for your help
`# Declare global variables
$fmSourcePath = "E:\Kistler\CoMo Services\Data\5336_L1.4345277\"
$shSourcePath = "E:\Kistler\CoMo Services\Data\5338_L1.5338_L1\"
$fmDesinationPath = "E:\Kistler XML Files\FM\"
$shDesinationPath = "E:\Kistler XML Files\SH\"
$fmWebAPI = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
$shWebAPI = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# the path to stored credential
$credPath = "E:\Kistler Script\Cred.xml"
$logFileName = "BatchLog.txt"
#Path to the error log file
$ErrorFileName = "E:\Kistler Script\errorlog.txt"
function Move_Kistler_Files {
param (
[string]$url,
[string]$SourcePath,
[string]$DestinationPath
)
try {
# check for stored credential
if ( Test-Path $credPath ) {
#crendetial is stored, load it
$cred = Import-CliXml -Path $credPath
} else {
# no stored credential then: create store, get credential and save it
$parent = split-path $credpath -parent
if ( -not ( test-Path $parent ) ) {
New-Item -ItemType Directory -Force -Path $parent
}
$cred = get-credential
$cred | Export-CliXml -Path $credPath
}
# Get the current batch id using the Web-API call
$result = Invoke-RestMethod -Uri $url -Credential $Cred
$BatchID = $result.Value
$BatchFolder = $DestinationPath + $BatchID
Write-Host $BatchFolder
# Create a new folder in the destination path based on the Batch ID
If(!(test-path $BatchFolder))
{
New-Item -ItemType Directory -Force -Path $BatchFolder | Out-Null
# Add the current date/time to the log file
$LogFile = $DestinationPath + $logFileName
# if file exist Update the last record with the batch end date
If((test-path $LogFile)){
$txt = get-content $LogFile
$txt[$txt.length - 1 ] = $txt[$txt.length - 1 ] + ", " + (Get-Date)
$txt | set-content $LogFile
}else{
#add a header row in the file
Add-Content -Path $LogFile -Value "BatchID, StartDate, EndDate"
}
# create a new record in the log file with current Batch Id and date as start of
batch indicator
$msg = $BatchID + ", " + (Get-Date)
Add-Content -Path $LogFile -Value $msg
}
##############################################################################
# Copy the Kistler XML files from the source to the destination
##############################################################################
# get al the Kistler XML files in the source folder
$Files = get-childitem -path $SourcePath -Recurse | Where-Object {$_.Extension -eq ".XML"}
| Sort-Object LastWriteTime -Descending
# If we have files to process do it
if ($Files.Length -gt 0) {
# read back the batch start and end dates from the log table
$LogFile = $DestinationPath + $logFileName
$txt = get-content $LogFile
# Get the latest Batch Id and it's start date
$FileMoveCount = 0
$FileNotMoveCount = 0
$ptr = 1
$batchArray =$txt[$txt.length - $ptr ].Split(",")
$MoveToPath = $DestinationPath + $batchArray[0]
$batchStartDate = $batchArray[1]
#Process each XML file
Foreach ($File in $Files ) {
$FileTime = $File.LastWriteTime
#write-host $File.FullName $File.Name $FileTime $MoveToPath $batchStartDate
#if the XML file's date-time is older than the batch start time, skip to the
previus Batch Id and start time
while ( ([DateTime]$FileTime -lt [DateTime]$batchStartDate) -and ($ptr -lt
($txt.length)-1) ) {
#Write a log for the number of files copied
if ($FileMoveCount -gt 0){
Add-Content -Path $ErrorFileName -Value ((Get-Date -Format "dd/MM/yyyy
HH:mm") + ": " + $FileMoveCount + " XML files moved to " + $MoveToPath)
$FileMoveCount = 0
}
$ptr++
$batchArray =$txt[$txt.length - $ptr ].Split(",")
$MoveToPath = $DestinationPath + $batchArray[0]
$batchStartDate = $batchArray[1]
#write-host $MoveToPath $batchStartDate
}
#Copy the XML file to the destination folder
if ([DateTime]$FileTime -ge [DateTime]$batchStartDate){
Move-Item $File.FullName -Destination ($MoveToPath + "\" + $File.Name)
$FileMoveCount++
}else{
Move-Item $File.FullName -Destination ($DestinationPath + "\NoBatch\" +
$File.Name)
$FileNotMoveCount++
}
}
#Write a log for the number of files copied
if ($FileMoveCount -gt 0){
Add-Content -Path $ErrorFileName -Value ((Get-Date -Format "dd/MM/yyyy HH:mm") + ": "
+ $FileMoveCount + " XML files moved to " + $MoveToPath)
}
if ($FileNotMoveCount -gt 0){
Add-Content -Path $ErrorFileName -Value ((Get-Date -Format "dd/MM/yyyy HH:mm") + ":
Could not find batch ID for " + $FileNotMoveCount + " XML files " )
}
}
}catch{
#Write the error
Write-Host "An error occurred:" -ForegroundColor red
Write-Host $_ -ForegroundColor red
Add-Content -Path $ErrorFileName -Value (Get-Date -Format "dd/MM/yyyy HH:mm") + ": " +
$_
}
}
### Process the FM Kistler files
Move_Kistler_Files $fmWebAPI $fmSourcePath $fmDesinationPath
### Process the SH Kistler files
Move_Kistler_Files $shWebAPI $shSourcePath $shDesinationPath`

Powershell Windows ACL

We are running the script mentioned below to change a heap of ACL permissions which needs to be down to the file level as we are migrating from one environment to another.
The script below is working for folders/subfolders but appears to fail when it comes to the actual files themselves.
$items = get-childitem \\file.location.com.au\project\people\user1 -recurse | select-object -property fullname
Foreach ($item in $items) {
# Get the ACL for an existing folder
$existingAcl = Get-Acl -Path '$item'
# Set the permissions that you want to apply to the folder
$permissions = 'SERVER\USER1', 'Read,Modify', 'ContainerInherit,ObjectInherit', 'None', 'Allow'
# Create a new FileSystemAccessRule object
$rule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $permissions
# Modify the existing ACL to include the new rule
$existingAcl.SetAccessRule($rule)
# Apply the modified access rule to the folder
$existingAcl | Set-Acl -Path '$ITEM'
}
As you can see we are getting the below error and im unsure why. Is someone able to see what im missing?
I have spent a lot of time with no progress on rectifying this issue.
At line:14 char:1
+ $existingAcl.SetAccessRule($rule)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Get-Acl : Cannot find path '$item' because it does not exist.
At line:5 char:16
+ $existingAcl = Get-Acl -Path '$item'
+ ~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (:) [Get-Acl], ItemNotFoundException
+ FullyQualifiedErrorId : GetAcl_PathNotFound_Exception,Microsoft.PowerShell.Commands.GetAcl
Command
You cannot call a method on a null-valued expression.
This should put you on the right track:
$items = get-childitem \\file.location.com.au\project\people\user1 -recurse | select-object -property fullname
# Set the permissions that you want to apply to the folder
$permissions = 'SERVER\User1', 'Read,Modify', 'Allow'
# Create a new FileSystemAccessRule object
$newaccessrule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $permissions
Foreach ($item in $items) {
# Get the ACL for an existing folder
$existingAcl = Get-Acl -Path $item.FullName
# Modify the existing ACL to include the new rule
$existingAcl.SetAccessRule($newaccessrule)
$existingAcl.SetAccessRuleProtection($false,$true)
# Apply the modified access rule to the folder
Set-Acl -Path $item.FullName -AclObject $existingAcl
}

Powershell Copy-Item Error when moving Bookmarks

One of my scripts is to move Google Chrome bookmarks from one machine on the network to another. When I run the script, it appears to run and then throws a Copy-Item error. Pretty sure there's something wrong with my file path, but I can't figure out what it is.
Code first, error follows:
[CmdletBinding()]
param(
[String]$SourceComputerName,
[String]$DestinationComputerName,
[String]$UserName
)
BEGIN {
$ErrorActionPreference = 'Continue'
$CMDOUT=#{ #This is used so that the function accepts -Verbose / -Debug parameters
Verbose=If ($PSBoundParameters.Verbose -eq $true) { $true } else { $false };
Debug=If ($PSBoundParameters.Debug -eq $true) { $true } else { $false }
}
$SourcePath = '\\' + $SourceComputerName + '\C$\users\' + $UserName + '\AppData\Local\Google\Chrome\User Data\Default' #Transfer Bookmarks from here
$DestinationPath = '\\' + $DestinationComputerName + '\C$\users\' + $UserName + '\AppData\Local\Google\Chrome\User Data\Default' #Transfer Bookmarks to here
}
PROCESS{
#Create copy of destination backup file, make sure not to overwrite other backup files that might exsist
If(Test-Path ($DestinationPath + '\Bookmarks')){
$i = 1
do{
$BackupPath = ($DestinationPath + '\Bookmarks') + '_' + $i.ToString('000') + '.old'
$i++
}
while(Test-Path $BackupPath)
Copy-Item -Path ($SourcePath + '\Bookmarks') -Destination $BackupPath #CMDOUT
}
#Copy Bookmarks to DestinationComputer
Copy-Item -Path ($SourcePath + '\Bookmarks') -Destination ($DestinationPath + '\Bookmarks') -Force #CMDOUT
#Replace the Chrome create Bookmark backup (.bak) file
Copy-Item -Path ($SourcePath + '\Bookmarks') -Destination ($DestinationPath + '\Bookmarks.bak') -Force #CMDOUT
#Copy Favicons (for bookmarks)
If(Test-Path ($DestinationPath + '\Favicons')){
Copy-Item -Path ($SourcePath + '\Favicons') -Destination ($DestinationPath + '\Favicons') -Force #CMDOUT
}
}
END{
}
}
Copy-Item : The network path was not found
At C:\Users\Shane.goldsberry\PowerShellScripts\PS1\MigrateChromeBookmarks.ps1:61 char:9
Copy-Item -Path ($SourcePath + '\Bookmarks') -Destination ($D ...
+ CategoryInfo : NotSpecified: (:) [Copy-Item], IOException
+ FullyQualifiedErrorId : System.IO.IOException,Microsoft.PowerShell.Commands.CopyItemCommand
Copy-Item : The network path was not found At C:\Users\Shane.goldsberry\PowerShellScripts\PS1\MigrateChromeBookmarks.ps1:63 char:9 Copy-Item -Path ($SourcePath + '\Bookmarks') -Destination ($D ...
+ CategoryInfo : NotSpecified: (:) [Copy-Item], IOException
+ FullyQualifiedErrorId : System.IO.IOException,Microsoft.PowerShell.Commands.CopyItemCommand

Escaping and eliminating spaces from PowerShell scripts to enable roaming of file type associations on Windows 10

I am trying to get output similar to this but preferably using Out-File.
<?xml version="1.0" encoding="UTF-8"?>
<DefaultAssociations>
<Association Identifier=".html" ProgId="FirefoxHTML" ApplicationName="ChromeHTML" />
</DefaultAssociations>
The problem I am having is that with Write-Host, extra spaces are being introduced along with the variable values. To use Out-File instead, when I try to concatenate each line with something like this:
$Out = $Out + '<Association Identifier="'$($Item.PSParentPath | Split-Path -Leaf)'"'
Out-File -FilePath c:\temp\test.xml $Out
I get an error
Unexpected token '$(' in expression or statement.
I'm so close to getting the desired output.
If the permissions are changed on %windir%\system32\OEMDefaultAssociations.xml to allow standard users to write, a login script can put a copy of what this script outputs into that file so that per user file type associations can roam between Windows 10 computers.
$UserChoiceKeys = Get-ChildItem "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FileExts\*\UserChoice"
$UserChoiceKeys = $UserChoiceKeys + (Get-ChildItem "HKCU:\SOFTWARE\Microsoft\Windows\Shell\Associations\UrlAssociations\*\UserChoice")
Write-Host '<?xml version="1.0" encoding="UTF-8"?>'
Write-Host '<DefaultAssociations>'
foreach ($Item in $UserChoiceKeys)
{
Write-Host -NoNewLine '<Association Identifier="'$($Item.PSParentPath | Split-Path -Leaf)'"'
$ProgID = $(Get-ItemProperty $Item.pspath -name "ProgID").ProgID
Write-Host -NoNewLine ' ProgId="'($ProgID)
$ApplicationKey = "HKLM:\SOFTWARE\Classes\"+$ProgID+"\Application"
$ApplicationName = $(Get-ItemProperty $ApplicationKey -name "ApplicationName" -errorAction SilentlyContinue).ApplicationName
Write-Host -NoNewLine '" ApplicationName="'$ApplicationName'" />'
Write-Host ''
}
Write-Host -NoNewline '</DefaultAssociations>'
Answer from OP moved to answer post by editor
$CustomAssociationsFilePath = "$($Env:userprofile)\CustomAssociations.xml"
$UserChoiceKeys = Get-ChildItem "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\FileExts\*\UserChoice"
$UserChoiceKeys += Get-ChildItem "HKCU:\SOFTWARE\Microsoft\Windows\Shell\Associations\UrlAssociations\*\UserChoice"
$nl = [Environment]::NewLine
$OutputData = '<?xml version="1.0" encoding="UTF-8"?>' + $nl + '<DefaultAssociations>'
foreach ($Item in $UserChoiceKeys)
{
$OutputData += $nl + '<Association Identifier="' + $($Item.PSParentPath | Split-Path -Leaf) + '"'
$ProgID = $(Get-ItemProperty $Item.pspath -name "ProgID").ProgID
$OutputData += ' ProgId="' + ($ProgID)
$ApplicationKey = "HKLM:\SOFTWARE\Classes\" + $ProgID + "\Application"
$ApplicationName = $(Get-ItemProperty $ApplicationKey -name "ApplicationName" -errorAction SilentlyContinue).ApplicationName
$OutputData += '" ApplicationName="' + $ApplicationName + '" />'
}
$OutputData += $nl + '</DefaultAssociations>'
Out-File -Encoding UTF8 -InputObject $OutputData -FilePath $CustomAssociationsFilePath

Resources