creating a remote repo of powershellgallery.com - is this possible? - powershell

Has anyone tried to or know how to setup a remote or cached repo within Artifactory for the powershellgallery?
I am unable to find anything even remotely talking about this online as well.
PSGallery URI is: https://www.powershellgallery.com/api/v2
I am beginning to think it was intentionally made by MS to not allow situations like that (but am looking for confirmation if that's the case)
NOTE: the intent here is that we will then have an internally accessible remote repo that is a copy of the PSGallery. Which then allows us to make sure we are scanning the modules and abiding by compliance regulations.
when it's added to Artifactory as a remote repo, its successful, but is empty.
Then, we set it up on Windows machine with register-PSRepository -Name psgallery-remote -SourceLocation myartifactoryuri (successful)
But when trying to do a find-module -name InvokeBuild -repository psgallery-remote it fails with no results.
When doing find-module -name InvokeBuild -Repository PSGallery it's successful.

You have to set up your repo and save PSGallery modules to it, then make it available to the local environment.
For a quick and dirty example to get stuff and use them:
New-Item -Path 'C:\' -Name 'LocalPSGallery' -ItemType Directory -Force -Verbose
Register-PSRepository -Name LocalPSGallery -SourceLocation 'C:\LocalPSGallery' -InstallationPolicy Trusted -Verbose
Get-PSRepository
Get-ChildItem -Path 'C:\LocalPSGallery'
# Results
<#
Note it is empty because it should be.
The above commands do not create a clone, it just sets up you local repo pointer.
#>
# Select a set number of modules as a test or by named group, etc
Find-Module -Name '*' |
Select-Object -First 9 |
Save-Module -Path 'C:\LocalPSGallery' -Force -ErrorAction SilentlyContinue
Get-ChildItem -Path 'C:\LocalPSGallery' # requested modules are listed
# Note still no list, because no path to your repo
Find-Module -Name Carbon -Repository LocalPSGallery
# Results
<#
PackageManagement\Find-Package : No match was found for the specified search
criteria and module name 'Carbon'. Try Get-PSRepository to see all available
registered module repositories.
#>
# Add the path
$env:PSModulePath
$env:PSModulePath = "$env:PSModulePath;C:\LocalPSGallery"
$env:PSModulePath
# Note still no list, because you've not installed anything
Find-Module -Name Carbon -Repository LocalPSGallery
# Results
<#
PackageManagement\Find-Package : No match was found for the specified search
criteria and module name 'Carbon'. Try Get-PSRepository to see all available
registered module repositories.
#>
# Try and install your module first
Install-Module -Name Carbon -Repository 'LocalPSGallery' -Verbose
# Results
<#
VERBOSE: Repository details, Name = 'LocalPSGallery', Location = 'C:\LocalPSGallery'; IsTrusted = 'True'; IsRegistered = 'True'.
VERBOSE: Using the provider 'PowerShellGet' for searching packages.
VERBOSE: Using the specified source names : 'LocalPSGallery'.
VERBOSE: Getting the provider object for the PackageManagement Provider 'NuGet'.
VERBOSE: The specified Location is 'C:\LocalPSGallery' and PackageManagementProvider is 'NuGet'.
VERBOSE: Total package yield:'0' for the specified package 'Carbon'.
PackageManagement\Install-Package : No match was found for the specified search
criteria and module name 'Carbon'. Try Get-PSRepository to see all
available registered module repositories.
#>
# Direclty import via FQDN
Import-Module -FullyQualifiedName 'C:\LocalPSGallery\Carbon' -Force -Verbose
# Results
<#
VERBOSE: Loading module from path 'C:\LocalPSGallery\Carbon\2.12.0\Carbon.psd1'.
VERBOSE: Loading 'FormatsToProcess' from path 'C:\LocalPSGallery\Carbon\2.12.0\Carbon.format.ps1xml'.
VERBOSE: Loading 'FormatsToProcess' from path 'C:\LocalPSGallery\Carbon\2.12.0\Formats\Carbon.Security.HttpUrlAcl.format.ps1xml'.
VERBOSE: Loading 'FormatsToProcess' from path 'C:\LocalPSGallery\Carbon\2.12.0\Formats\Schedule.Service.RegisteredTask.format.ps1xml'.
VERBOSE: Populating RepositorySourceLocation property for module Carbon.
VERBOSE: Loading module from path 'C:\LocalPSGallery\Carbon\2.12.0\Carbon.psm1'.
VERBOSE: Importing function 'Add-CGroupMember'.
VERBOSE: Importing function 'Add-CTrustedHost'.
...
#>
Find-Module -Name Carbon -Repository LocalPSGallery
# Results
<#
PackageManagement\Find-Package : No match was found for the specified search criteria
and module name 'Carbon'. Try Get-PSRepository to see all available
registered module repositories.
#>
# The below will work as expected
Get-Module -Name Carbon
Get-Module -ListAvailable
Here is a blog on the use case as well.
MS does provide the full details offline PSGallery deployment, See: Working with Private PowerShellGet Repositories
Of course, downloading all modules is going to take a very long time, and again, has would need to be done regularly to stay current.
So, on a pristine system, and using the details from the MS doc, you'd end up with something link this:
# Create a new location for your repo
New-Item -Path 'C:\' -Name 'LocalPSGallery' -ItemType Directory -Force -Verbose
# Update your path for your repo
$env:PSModulePath
$env:PSModulePath = "$env:PSModulePath;C:\LocalPSGallery"
$env:PSModulePath
# While online, install required resources
'PackageManagement', 'OfflinePowerShellGetDeploy' |
ForEach-Object {Install-Module -Name $PSitem -Force -Verbose}
Get-PSRepository
# Register a location for your repo
$CreateLocalPSGallery = #{
Name = 'LocalPSGallery'
SourceLocation = 'C:\LocalPSGallery'
ScriptSourceLocation = 'C:\LocalPSGallery'
InstallationPolicy = 'Trusted'
}
Register-PSRepository #CreateLocalPSGallery -Verbose
Get-PSRepository
Get-ChildItem -Path 'C:\LocalPSGallery'
# Publish from the PSGallery to your local Repository
Find-Module -Name '*' |
Select-Object -First 9 |
ForEach-Object {
$PublishFromLocalRepo = #{
Name = $PSItem.Name
Provider = 'NuGet'
Source = 'https://www.powershellgallery.com/api/v2'
Path = 'C:\LocalPSGallery'
Force = $True
ErrorAction = 'SilentlyContinue'
}
Save-Package #PublishFromLocalRepo
}
# Validate resource download
Get-ChildItem -Path 'C:\LocalPSGallery'
# Validate all repo resources
Find-Module -Name '*' -Repository LocalPSGallery
Find-Module -Name '*json*' |
Select-Object -First 3
# Make you repo the default - remote all other repos
Unregister-PSRepository -Name PSGallery -Verbose
Get-PSRepository
# Test your repo as the default
Find-Module -Name '*' -Repository LocalPSGallery
Find-Module -Name '*'
# After testing, reset the default
Register-PSRepository -Default -Verbose
Get-PSRepository

You should configure Artifactory remote repository as the following :
Url: https://www.powershellgallery.com/
NuGet Download Context Path : api/v2/package
NuGet Feed Context Path: api/v2
Link for JFrog documentation on NuGet Remote Repositories : https://www.jfrog.com/confluence/display/JFROG/NuGet+Repositories#NuGetRepositories-RemoteRepositories

Related

Powershell copy all folders and files with certain extension

I have one package on my Windows machine and another package on a remote server.
The first one is -> C:\Users\One. It contains the following files:
adapter.jsx
result.js
system.jsx
moment.js
readme.txt
package called info that contains two files -> logger.jsx and date.js.
Another one is a remote target directory -> /mnt/media/Two. It is currently empty. The user and host for it are: $userAndHost = "user#foo.bar"
I want to copy all the packages and files of extensions .jsx and .js from package One to package Two. It's required to use scp here since this is a copy between two different platforms.
What I tried:
get all the items within the package:
Get-ChildItem -Path "C:\Users\One" -Recurse
filter items by certain extension, in my case they are .jsx and .js:
Get-ChildItem -Path "C:\Users\One" -Recurse | Where-Object {$_.extension -in ".js",".jsx"}
do the secure copy (scp) - I didn't come up with the script here.
Please, help me finish the script.
Hi i think you need something like this.
I write a code for you, tested working.
#Set execution policy to bypass
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -Force
#install Posh-SSH from powershell gallery
#https://www.powershellgallery.com/packages/Posh-SSH/2.0.2
Install-Module -Name Posh-SSH -RequiredVersion 2.0.2
#import module
Import-Module Posh-SSH
#get all the items within the package in the path:
$path = 'C:\Users\One'
$items = (Get-ChildItem -Path $path -Name -File -Include ( '*.jsx', '*.js') -Recurse)
#Need destination credential
$credential = Get-Credential
#copy selected items to destination via scp
$items | ForEach-Object {
Set-SCPFile -ComputerName 'SCP-SERVER-HOST-HERE' -Credential $credential -RemotePath '/mnt/media/Two' -LocalFile "$path\$_"
}
Hope this helps you

Generate a pdf from powershell

I'm trying to generate a PDF with powershell but I don't know how to proceed. I already tried to use Itext 7 but I don't know how to make it work.
When i try to install Itext7 on powershell i have this error message :
No match found for the specified search criteria and the itext7 package name. Use
Get-PackageSource to display for all available registered package sources.
Could I have some help?
Thanks in advance
The combination of PowerShell dependencies can be problematic as they need to be of a known working group in time and 7.1.14 was touted as a light solution so see later TL;DR edits or others comments below, [Later EDIT for more recent heavier list of 7.2.# dependencies see answer by #paul-oneill ] (https://stackoverflow.com/a/75280860/10802527) and run as Admin perhaps different to a normal user. So follow these steps carefully as some may downgrade your current settings.
MOST IMPORTANT use a project directory and watch that your prompt is located in that folder to ensure you are not running in the default PowerShell directory. I use a shortcut where the target directory is "blank/empty" thus defaults to the current working folder.
1st Check:-
project folder>[Net.ServicePointManager]::SecurityProtocol
should return either Tls12 or Tls13 we need it to be 1.2 so keep a note if yours is set to Tls13 and run this line.
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
we may need to possibly change package provider so first check if nuget includes https://www.nuget.org/api/v2/:-
> Get-PackageSource
Name ProviderName IsTrusted Location
---- ------------ --------- --------
nuget.org NuGet False https://www.nuget.org/api/v2/
PSGallery PowerShellGet False https://www.powershellgallery.com/api/v2
If not you can add it as
Register-PackageSource nuget.org https://www.nuget.org/api/v2/ -ProviderName NuGet
now you should be able to install the dlls as follows
Install-Package -Name "itext7" -ProviderName NuGet -RequiredVersion 7.1.14 -Destination . -SkipDependencies
Install-Package -Name Portable.BouncyCastle -ProviderName NuGet -RequiredVersion 1.8.9.0 -Destination . -SkipDependencies
Install-Package -Name Common.Logging -ProviderName NuGet -RequiredVersion 3.4.1.0 -Destination . -SkipDependencies
Install-Package -Name Common.Logging.Core -ProviderName NuGet -RequiredVersion 3.4.1.0 -Destination . -SkipDependencies
Double check your folder has the correct structure
Note the order and location of the script is critical for correct loading
Add-Type -Path (Join-Path $PSScriptRoot ".\Common.Logging.Core.3.4.1\lib\net40\Common.Logging.Core.dll")
Add-Type -Path (Join-Path $PSScriptRoot ".\Common.Logging.3.4.1\lib\net40\Common.Logging.dll")
Add-Type -Path (Join-Path $PSScriptRoot ".\Portable.BouncyCastle.1.8.9\lib\net40\BouncyCastle.Crypto.dll")
Add-Type -Path (Join-Path $PSScriptRoot ".\itext7.7.1.14\lib\net40\itext.io.dll")
Add-Type -Path (Join-Path $PSScriptRoot ".\itext7.7.1.14\lib\net40\itext.layout.dll")
Add-Type -Path (Join-Path $PSScriptRoot ".\itext7.7.1.14\lib\net40\itext.kernel.dll")
$pdfDocuFilename = (join-path $PSScriptRoot "My1st.pdf")
$pdfWriter = [iText.Kernel.Pdf.PdfWriter]::new($pdfDocuFilename)
$pdfdocument = [iText.Kernel.Pdf.PdfDocument]::new($pdfWriter)
$pdfdocument.AddNewPage()
$pdfdocument.Close()
This will produce an empty file but proves all is well, and you can start running other examples such as the one suggested by S_G, so after the loading Add-Type block replace my blank example with
[string] $DEST = "HelloWorld.pdf"
$pdfWriter = [iText.Kernel.Pdf.PdfWriter]::new($DEST)
$pdf = [iText.Kernel.Pdf.PdfDocument]::new($pdfWriter)
$document = [iText.Layout.Document]::new($pdf)
$document.Add([iText.Layout.Element.Paragraph]::new("Hello World! from Powershell"))
$pdf.Close()
... Good Luck.
The versions above were for a fixed point in time when user blogs had verified that 7.1 mixes worked without much conflict, the aim is to produce a group of standalone files working within Net40 environment, but time moves on and you should ensure you are using a newer mix. HOWEVER everything changed in 7.1.15 as a phenomenally greater list of dependencies is now required for Net 4.5 and now 4.6.1 although, packages/itext7/7.2.1 itself still works with
packages/Portable.BouncyCastle/1.8.9 + and common logging is still 3.4.1
Below is the code for a PowerShell Script which outputs a PDF with "Hello World!" written on it. It mirrors the functionality of iText 7 basic Hello World example. You can change it as per your requirement.
Add-Type -Path "C:\temp\Common.Logging.Core.dll"
Add-Type -Path "C:\temp\Common.Logging.dll"
Add-Type -Path "C:\temp\BouncyCastle.Crypto.dll"
Add-Type -Path "C:\temp\itext.io.dll"
Add-Type -Path "C:\temp\itext.layout.dll"
Add-Type -Path "C:\temp\itext.kernel.dll"
[string] $DEST = "C:\files\HelloWorldPowerShell.pdf"
$pdfWriter = [iText.Kernel.Pdf.PdfWriter]::new($DEST)
$pdf = [iText.Kernel.Pdf.PdfDocument]::new($pdfWriter)
$document = [iText.Layout.Document]::new($pdf)
$document.Add([iText.Layout.Element.Paragraph]::new("Hello World!"))
$pdf.Close()
I found some good info here what DLLs need to be loaded via add-type ... https://renenyffenegger.ch/notes/design/graphic/pdf/tools/iText/index
Through trial & error I found loading the below works for itext7 versions 7.2.0, 7.2.4 & 7.2.5.
# DLL list - https://www.nuget.org/packages/itext7/
$dll_list = #(
"$my_ScriptDir\DLL_7.2.4\BouncyCastle.Crypto.dll"
"$my_ScriptDir\DLL_7.2.4\Common.Logging.Core.dll"
"$my_ScriptDir\DLL_7.2.4\Common.Logging.dll"
"$my_ScriptDir\DLL_7.2.4\itext.commons.dll"
"$my_ScriptDir\DLL_7.2.4\itext.forms.dll"
"$my_ScriptDir\DLL_7.2.4\itext.io.dll"
"$my_ScriptDir\DLL_7.2.4\itext.kernel.dll"
"$my_ScriptDir\DLL_7.2.4\itext.layout.dll"
"$my_ScriptDir\DLL_7.2.4\Microsoft.Bcl.AsyncInterfaces.dll"
"$my_ScriptDir\DLL_7.2.4\Microsoft.Extensions.DependencyInjection.Abstractions.dll"
"$my_ScriptDir\DLL_7.2.4\Microsoft.Extensions.DependencyInjection.dll"
"$my_ScriptDir\DLL_7.2.4\Microsoft.Extensions.Logging.Abstractions.dll"
"$my_ScriptDir\DLL_7.2.4\Microsoft.Extensions.Logging.dll"
"$my_ScriptDir\DLL_7.2.4\Microsoft.Extensions.Options.dll"
"$my_ScriptDir\DLL_7.2.4\Microsoft.Extensions.Primitives.dll"
"$my_ScriptDir\DLL_7.2.4\System.Diagnostics.DiagnosticSource.dll"
"$my_ScriptDir\DLL_7.2.4\System.Memory.dll"
"$my_ScriptDir\DLL_7.2.4\System.Runtime.CompilerServices.Unsafe.dll"
"$my_ScriptDir\DLL_7.2.4\System.Threading.Tasks.Extensions.dll"
"$my_ScriptDir\DLL_7.2.4\System.ValueTuple.dll"
"$my_ScriptDir\DLL_7.2.4\Newtonsoft.Json.dll"
)
# Loop & load DLLs
foreach ($dll in $dll_list)
{
Write-Host "Loading $dll" -ForegroundColor Green
try { Add-Type -Path "$dll"}
catch { $dll.Exception.LoaderExceptions }
}
Just my 2 cents but the above code does NOT work with Itext7 7.2.1 (after modifying for proper paths).
Wish I'd seen this post last week - wasted most of several days pulling hair out over 7.2.1 not behaving itself. :(

Why does a script from PSGallery not have a Zone.Identifier stream?

A NuGet repository, such as PSGallery, is clearly a remote system. Why do scripts installed from there not have a Zone.Identifier stream?
PS C:\> Find-Script -Repository PSGallery -Name Test-RPC | Install-Script -Scope CurrentUser
Untrusted repository
You are installing the scripts from an untrusted repository. If you trust this repository, change its InstallationPolicy value by running the
Set-PSRepository cmdlet. Are you sure you want to install the scripts from 'https://www.powershellgallery.com/api/v2'?
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "N"): Y
PS C:\> Get-Item -Path $Env:USERPROFILE\Documents\WindowsPowerShell\Scripts\Test-RPC.ps1 -Stream *
PSPath : Microsoft.PowerShell.Core\FileSystem::C:\Users\lit\Documents\WindowsPowerShell\Scripts\Test-RPC.ps1::$DATA
PSParentPath : Microsoft.PowerShell.Core\FileSystem::C:\Users\lit\Documents\WindowsPowerShell\Scripts
PSChildName : Test-RPC.ps1::$DATA
PSDrive : C
PSProvider : Microsoft.PowerShell.Core\FileSystem
PSIsContainer : False
FileName : C:\Users\lit\Documents\WindowsPowerShell\Scripts\Test-RPC.ps1
Stream : :$DATA
Length : 7771
The question is:
How can I ensure that users with ExecutionPolicy of RemoteSigned will need to use the signature? How will PowerShell know it is a remote file without a Zone.Identifier stream?
Is there any reason that package providers, especially untrusted ones, should not create a Zone.Identifier stream?
Continuing from my comment.
Clear-Host
$Url = 'https://www.powershellgallery.com/packages/Test-RPC/1.0/Content/Test-RPC.ps1'
$output = 'C:\Temp\Test-RPC.ps1'
$ValidateFile = {
Try {Get-Item -Path $output -Stream Zone.Identifier -ErrorAction Stop}
Catch [System.Exception]
{
Write-Warning -Message 'Error'
$PSItem.Exception.Message
}
}
Remove-Item -Path $output -Force -ErrorAction SilentlyContinue
Invoke-WebRequest -Uri $url -OutFile $output
Remove-Item -Path $output -Force -ErrorAction SilentlyContinue
$wc = New-Object System.Net.WebClient
$wc.DownloadFile($url, $output)
& $ValidateFile
Remove-Item -Path $output -Force -ErrorAction SilentlyContinue
(New-Object System.Net.WebClient).DownloadFile($url, $output)
& $ValidateFile
Import-Module -Name BitsTransfer
Remove-Item -Path $output -Force -ErrorAction SilentlyContinue
Start-BitsTransfer -Source $url -Destination $output
& $ValidateFile
Remove-Item -Path $output -Force -ErrorAction SilentlyContinue
Start-BitsTransfer -Source $url -Destination $output -Asynchronous
& $ValidateFile
# Results
<#
WARNING: Error
Could not open the alternate data stream 'Zone.Identifier' of the file 'C:\Temp\Test-RPC.ps1'.
WARNING: Error
Could not open the alternate data stream 'Zone.Identifier' of the file 'C:\Temp\Test-RPC.ps1'.
WARNING: Error
Could not open the alternate data stream 'Zone.Identifier' of the file 'C:\Temp\Test-RPC.ps1'.
WARNING: Error
JobId DisplayName TransferType JobState OwnerAccount
----- ----------- ------------ -------- ------------
f5f04c93-4247-4095-8d9a-587b26d64d26 BITS Transfer Download Connecting 570A5E12-BA93-4\WDAGUtilityAccount
Cannot find path 'C:\Temp\Test-RPC.ps1' because it does not exist.
#>
Doing the aforementioned download using real curl.exe also does not add the internet ADS tag. Manually download curl.exe via your browser.
https://curl.se/windows
Check the ADS data, note the internet tag is there.
The download using real curl.exe, in cmd.exe
curl.exe -O https://curl.se/windows/dl-7.76.0/curl-7.76.0-win64-mingw.zip
Check the ADS data, not the internet tag is not there.
Lastly, as for this ...
How can I ensure that users with ExecutionPolicy of RemoteSigned.
As documented and publically stated by MSFT, EP's are not a security boundary and that was never their design.
RemoteSigned ExecutionPolicy:
• Allows scripts to run
• Requires that all scripts ***downloaded from the Internet*** must
be ***digitally signed by a publisher you specified as trusted***.
This includes scripts received via email and instant messaging
platforms.
• Will not require digital signing of scripts written on a local
computer
• May allow running of malicious scripts from other sources
They are there to prevent accidental code runs. EP's can easily be bypassed and that too is fully documented/demo'd
15 Ways to Bypass the PowerShell Execution Policy:
https://blog.netspi.com/15-ways-to-bypass-the-powershell-execution-policy
Detecting Offensive PowerShell Attack Tools:
https://adsecurity.org/?p=2604
One can open any script in the ISE/VSCode, etc., select all, and hit run and the EP has no control over that. EP, is for running scripts by name, meaning, calling from the consolehost, scheduled task, etc.
Nothing stops a user from opening the script, removing the sigblock, and saving the script with a new name, and running it or creating a blank script, copy the content from the clocked script, saving and running.
PowerShell risk management/Security controls/mitigation are all the normal network/client stuff as well as all about full enterprise logging, auditing, and early alerting/effect response when strangeness is seen/discovered.

Substitute icacls.exe with powershell

I want to replace the following CMD command with a Powershell command:
Icacls.exe "%SystemDrive%\xxx" /grant *S-X-X-XX-XXX:(CI)(OI)(F) /t /c
I also know how to do this with Icacls, but I think there is a nicer way to do it with the PowerShell.
I would be happy if someone could help me in this regard. :-)
Thanks.
The built-in help files, provide you the guidance for this.
Set-Acl Changes the security descriptor of a specified item, such
as a file or a registry key.
# Get specifics for a module, cmdlet, or function
(Get-Command -Name Get-Acl).Parameters
(Get-Command -Name Get-Acl).Parameters.Keys
<#
# Results
Path
InputObject
LiteralPath
Audit
AllCentralAccessPolicies
Filter
Include
Exclude
...
#>
Get-help -Name Get-Acl -Examples
<#
# Results
Get-Acl C:\Windows
Get-Acl -Path "C:\Windows\k*.log" |
Format-List -Property PSPath, Sddl
Get-Acl -Path "C:/Windows/k*.log" -Audit |
ForEach-Object { $_.Audit.Count }
Get-Acl -Path "HKLM:\System\CurrentControlSet\Control" |
Format-List
Get-Acl -InputObject (Get-StorageSubsystem -Name S087)
#>
Get-help -Name Get-Acl -Full
Get-help -Name Get-Acl -Online
(Get-Command -Name Set-Acl).Parameters
(Get-Command -Name Set-Acl).Parameters.Keys
<#
# Results
Path
InputObject
LiteralPath
AclObject
CentralAccessPolicy
ClearCentralAccessPolicy
Passthru
Filter
Include
Exclude
...
#>
Get-help -Name Set-Acl -Examples
<#
# Results
$DogACL = Get-Acl -Path "C:\Dog.txt"
Set-Acl -Path "C:\Cat.txt" -AclObject $DogACL
Get-Acl -Path "C:\Dog.txt" |
Set-Acl -Path "C:\Cat.txt"
$NewAcl = Get-Acl File0.txt
Get-ChildItem -Path "C:\temp" -Recurse -Include "*.txt" -Force |
Set-Acl -AclObject $NewAcl
#>
Get-help -Name Set-Acl -Full
Get-help -Name Set-Acl -Online
There are other modules via the Microsoft PowerShellGallery.com for you to leverage as well.
Find-Module -Name '*acl*', '*ntfs*' |
Format-Table -AutoSize
<#
# Results
Version Name Repository Description
------- ---- ---------- -----------
1.0.1 ACL-Permissions PSGallery A couple of ACL utilities, for repairing c...
1.30.1.28 ACLReportTools PSGallery Provides Cmdlets for reporting on Share ACLs.
1.7 ACLHelpers PSGallery Modules to help work with ACLs (Access Control Rights)
1.0.1.0 ACLCleanup PSGallery A set of tools to help you clean your files...
0.1.2 ACLTools PSGallery Module for managing NTFS Acls on files and folders
...
0.4 FileAclTools PSGallery Tools for quickly fixing file system ACLs
...
4.2.6 NTFSSecurity PSGallery Windows PowerShell Module for managing file ...
1.4.1 cNtfsAccessControl PSGallery The cNtfsAccessControl module contains DSC re...
1.0 NTFSPermissionMigration PSGallery This module is used as a wrapper to the popular ...
#>
So, for what you are showing
# Review current settings
Get-Acl -Path $env:SystemDrive |
Format-List -Force
<#
# Results
Path : Microsoft.PowerShell.Core\FileSystem::C:\Windows\system32
Owner : NT SERVICE\TrustedInstaller
Group : NT SERVICE\TrustedInstaller
Access : CREATOR OWNER Allow 268435456
NT AUTHORITY\SYSTEM Allow 268435456
NT AUTHORITY\SYSTEM Allow Modify, Synchronize
BUILTIN\Administrators Allow 268435456
BUILTIN\Administrators Allow Modify, Synchronize
BUILTIN\Users Allow -1610612736
BUILTIN\Users Allow ReadAndExecute, Synchronize
NT SERVICE\TrustedInstaller Allow 268435456
NT SERVICE\TrustedInstaller Allow FullControl
APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES Allow ReadAndExecute, Synchronize
APPLICATION PACKAGE AUTHORITY\ALL APPLICATION PACKAGES Allow -1610612736
APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES Allow ReadAndExecute, Synchronize
APPLICATION PACKAGE AUTHORITY\ALL RESTRICTED APPLICATION PACKAGES Allow -1610612736
Audit :
Sddl : O:S-1-5-80-956008885-34...
#>
Description
The Set-Acl cmdlet changes the security descriptor of a specified
item, such as a file or a registry key, to match the values in a
security descriptor that you supply.
To use Set-Acl, use the Path or InputObject parameter to identify the
item whose security descriptor you want to change. Then, use the
AclObject or SecurityDescriptor parameters to supply a security
descriptor that has the values you want to apply. Set-Acl applies the
security descriptor that is supplied. It uses the value of the
AclObject parameter as a model and changes the values in the item's
security descriptor to match the values in the AclObject parameter.
Parameters
-AclObject Specifies an ACL with the desired property values. Set-Acl changes the ACL of item specified by the Path or InputObject parameter
to match the values in the specified security object.
You can save the output of a Get-Acl command in a variable and then
use the AclObject parameter to pass the variable, or type a Get-Acl
command.
TABLE 1 Type: Object
Position: 1 Default value: None Accept
pipeline input: True (ByValue) Accept wildcard characters: False
So, you just do something like this... as per the above examples
$AclSettings = 'WhatEverSettingsYouWant'
Set-Acl -Path $env:SystemDrive -AclObject $AclSettings
A similar question on StackOverflow is here:
Setting Inheritance and Propagation flags with set-acl and
Powershell
Then there is this guidance:
Here's the MSDN page describing the flags and what is the result of
their various combinations.
https://msdn.microsoft.com/en-us/library/ms229747(v=vs.100).aspx
InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit
PropagationFlags.None
Here's some succinct PowerShell code to apply new permissions to a
folder by modifying its existing ACL (Access Control List).
# Get the ACL for an existing folder
$existingAcl = Get-Acl -Path 'C:\DemoFolder'
# Set the permissions that you want to apply to the folder
$permissions = $env:username, '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 'C:\DemoFolder'
<#
Each of the values in the $permissions variable list pertain to the parameters of this constructor for the FileSystemAccessRule class.
#>

Powershell: Get Size of Windows User Directory (C:\Users\<UserName>)

I need to get the size of all user folders across 200 VMs. I need -force to see the hidden folders of other users.
$objFSO = New-Object -com Scripting.FileSystemObject
"{0:N2}" -f (($objFSO.GetFolder("C:\users").Size) / 1MB) + " MB"
Works fine for C:\Temp, for example, but returns 0.00 MB for C:\Users, even on my local, where I am an admin.
Get-ChildItem -path c:\users -force -recurse | Measure-Object length -sum
Throws security exceptions--even on my own user folder, with admin, running in an elevated PS session.
+ CategoryInfo : PermissionDenied: (C:\Users\YuriPup\Documents\My Music:String) [Get-ChildItem], UnauthorizedAccessException
+ FullyQualifiedErrorId : DirUnauthorizedAccessError,Microsoft.PowerShell.Commands.GetChildItemCommand
No reason to stress out over this or do it from scratch (unless it's a learning exercise). There are many examples all over the web showing how to do this. There are even pre-built modules you can use from the MS powershellgallery.com, that you can install directly.
Find-Module -Name '*folder*' | Format-Table -AutoSize
Version Name Repository Description
------- ---- ---------- -----------
1.6.8 PSFolderSize PSGallery This module enables you to gather folder size information, and output the results easily in various ways. GitHub Repo: ...
1.3.1 GetSTFolderSize PSGallery Get folder sizes blazingly fast, with the Svendsen Tech Get-STFolderSize function. Also measures and displays how long ...
1.0 cEPRSFolderPermissions PSGallery cEPRSFolderPermissions Module helps in providing the required permissions for a User to the respective Folder
1.0.4 FolderBookmarks PSGallery The module provides functions to manage and use bookmarks that point to folders.
1.0 cFolderQuota PSGallery DSC Resource for Creating Quotas and Quotas Templates
1.0.0.0 ExplorerFolder PSGallery Manages the Explorer Shell
2.0.0 FolderEncoder PSGallery Encode files from folder for(for example) uploading to cloud
1.0 DeleteSearchFolders PSGallery Module used for finding and deleting Search folders from an Exchange Mailbox
1.0.3 Illallangi.MailFolders PSGallery Manage Outlook Folders
Can you try with this script? you can get the directory size with gci command.
'{0:N2} GB' -f ((gci –force C:\Users\$directoryName –Recurse -ErrorAction SilentlyContinue| measure Length -s).sum / 1Gb)
same you can loop for all users in c:\users directory and execute it on given list of remote machines.
# List of servers
$Computers = #("Machine1", "Machine2", "Machine3")
#Start all jobs in parallel
ForEach($Computer in $Computers)
{
Write-Host $Computer
$Depth = 1
$Path = 'C:\Users\'
$Levels = '/*' * $Depth
Get-ChildItem -Directory $Path/$Levels |
ForEach-Object
{
$name = ($_.FullName -split '[\\/]')[-$Depth]
#Write-Host $name;
$wmidiskblock = "'{0:N2} GB' -f ((gci –force C:\Users\$name –Recurse -ErrorAction SilentlyContinue| measure Length -s).sum / 1Gb)";
Write-Host $wmidiskblock;
}
Start-Job -scriptblock $wmidiskblock -ArgumentList $Computer
}
Get-Job | Wait-Job
$out = Get-Job | Receive-Job
$out |export-csv 'c:\temp\result.csv'